[llvm] [BOLT] Fix pwrite assertion failure when patching .dynsym at high offsets (PR #198569)

Jinjie Huang via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 2 06:38:39 PDT 2026


https://github.com/Jinjie-Huang updated https://github.com/llvm/llvm-project/pull/198569

>From 063aba38ea11eaf48abb19aac56ea178cfa7ee4a Mon Sep 17 00:00:00 2001
From: huangjinjie <huangjinjie at bytedance.com>
Date: Tue, 19 May 2026 23:58:53 +0800
Subject: [PATCH 1/2] fix .dynsym pwrite problem

---
 bolt/lib/Rewrite/RewriteInstance.cpp |  8 +++
 bolt/test/X86/dynsym-pwrite.test     | 89 ++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)
 create mode 100644 bolt/test/X86/dynsym-pwrite.test

diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index cb5cba800a9d7..a6178bfff0ec8 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -5619,6 +5619,11 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
   assert((DynSymSection || BC->IsStaticExecutable) &&
          "dynamic symbol table expected");
   if (DynSymSection) {
+    uint64_t SavedPos = Out->os().tell();
+    uint64_t RequiredPos = DynSymSection->sh_offset + DynSymSection->sh_size;
+    if (SavedPos < RequiredPos)
+      Out->os().seek(RequiredPos);
+
     updateELFSymbolTable(
         File,
         /*IsDynSym=*/true,
@@ -5630,6 +5635,9 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
                            DynSymSection->sh_offset + Offset);
         },
         [](StringRef) -> size_t { return 0; });
+
+    if (SavedPos < RequiredPos)
+      Out->os().seek(SavedPos);
   }
 
   if (opts::RemoveSymtab)
diff --git a/bolt/test/X86/dynsym-pwrite.test b/bolt/test/X86/dynsym-pwrite.test
new file mode 100644
index 0000000000000..7885ba13fdfcc
--- /dev/null
+++ b/bolt/test/X86/dynsym-pwrite.test
@@ -0,0 +1,89 @@
+## Check that llvm-bolt can properly update the .dynsym section
+## when it is located at a high offset in the ELF file.
+
+
+# REQUIRES: system-linux
+
+# RUN: yaml2obj %s -o %t.so
+# RUN: llvm-bolt %t.so -o %t.so.bolt 2>&1 | FileCheck %s
+
+# CHECK-NOT: We don't support extending the stream
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+ProgramHeaders:
+  - Type:            PT_LOAD
+    Flags:           [ PF_R, PF_X ]
+    VAddr:           0x1000
+    Align:           0x1000
+    FirstSec:        .text
+    LastSec:         .eh_frame
+  - Type:            PT_LOAD
+    Flags:           [ PF_R, PF_W ]
+    VAddr:           0x2000
+    Align:           0x1000
+    FirstSec:        .dynamic
+    LastSec:         .dynsym
+  - Type:            PT_DYNAMIC
+    Flags:           [ PF_R, PF_W ]
+    VAddr:           0x2000
+    FirstSec:        .dynamic
+    LastSec:         .dynamic
+  - Type:            PT_GNU_EH_FRAME
+    Flags:           [ PF_R ]
+    VAddr:           0x1010
+    FirstSec:        .eh_frame_hdr
+    LastSec:         .eh_frame_hdr
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x1000
+    Content:         'C3' # ret
+    Size:            0x1
+  - Name:            .eh_frame_hdr
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1010
+    Content:         '011B033B0C00000001000000F0FFFFFF28000000'
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1020
+    Content:         '1400000000000000017A5200017810011B0C070890010000140000001C000000C0FFFFFF010000000000000000000000'
+  - Name:            .dynamic
+    Type:            SHT_DYNAMIC
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x2000
+    AddressAlign:    0x1000
+    Entries:
+      - Tag:             DT_SYMTAB
+        Value:           0x2100
+      - Tag:             DT_NULL
+        Value:           0x0
+  - Name:            .dynstr
+    Type:            SHT_STRTAB
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2050
+  - Name:            .dynsym
+    Type:            SHT_DYNSYM
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2100
+    Link:            .dynstr
+DynamicSymbols:
+  - Name:            _DYNAMIC
+    Binding:         STB_GLOBAL
+    Section:         .dynamic
+Symbols:
+  - Name:            _start
+    Section:         .text
+    Value:           0x1000
+    Size:            0x1
+    Binding:         STB_GLOBAL
+    Type:            STT_FUNC
+...

>From ffa1abb1cb4b45bf87a895d0e518458e36eca476 Mon Sep 17 00:00:00 2001
From: huangjinjie <huangjinjie at bytedance.com>
Date: Tue, 2 Jun 2026 21:38:14 +0800
Subject: [PATCH 2/2] Implement safePWrite wrapper to generalize the usage of
 pwrite in BOLT

---
 bolt/include/bolt/Core/BinarySection.h        |  2 +-
 .../bolt/Rewrite/MachORewriteInstance.h       |  3 +-
 bolt/include/bolt/Utils/Utils.h               |  3 ++
 bolt/lib/Core/BinarySection.cpp               | 12 ++---
 bolt/lib/Rewrite/MachORewriteInstance.cpp     | 14 +++---
 bolt/lib/Rewrite/RewriteInstance.cpp          | 45 +++++++------------
 bolt/lib/Utils/Utils.cpp                      | 22 +++++++++
 bolt/unittests/Core/BinaryContext.cpp         | 31 +++++++++----
 8 files changed, 79 insertions(+), 53 deletions(-)

diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h
index 154a8d12de5ce..cafd55e7acf6c 100644
--- a/bolt/include/bolt/Core/BinarySection.h
+++ b/bolt/include/bolt/Core/BinarySection.h
@@ -478,7 +478,7 @@ class BinarySection {
 
   /// Flush all pending relocations to patch original contents of sections
   /// that were not emitted via MCStreamer.
-  void flushPendingRelocations(raw_pwrite_stream &OS,
+  void flushPendingRelocations(raw_fd_ostream &OS,
                                SymbolResolverFuncTy Resolver);
 
   /// Change contents of the section. Unless the section has a valid SectionID,
diff --git a/bolt/include/bolt/Rewrite/MachORewriteInstance.h b/bolt/include/bolt/Rewrite/MachORewriteInstance.h
index fc1dd12b7e06e..ef323aab6bc8d 100644
--- a/bolt/include/bolt/Rewrite/MachORewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/MachORewriteInstance.h
@@ -62,8 +62,7 @@ class MachORewriteInstance {
   void runOptimizationPasses();
   void emitAndLink();
 
-  void writeInstrumentationSection(StringRef SectionName,
-                                   raw_pwrite_stream &OS);
+  void writeInstrumentationSection(StringRef SectionName, raw_fd_ostream &OS);
   void rewriteFile();
 
 public:
diff --git a/bolt/include/bolt/Utils/Utils.h b/bolt/include/bolt/Utils/Utils.h
index 9baee7d94066d..3b4a17e919d00 100644
--- a/bolt/include/bolt/Utils/Utils.h
+++ b/bolt/include/bolt/Utils/Utils.h
@@ -76,6 +76,9 @@ std::optional<StringRef> getLTOCommonName(const StringRef Name);
 // If the expression is defining the CFA, return std::nullopt.
 std::optional<uint8_t> readDWARFExpressionTargetReg(StringRef ExprBytes);
 
+void safePWrite(raw_fd_ostream &OS, const char *Src, size_t Size,
+                uint64_t Offset);
+
 } // namespace bolt
 
 bool operator==(const llvm::MCCFIInstruction &L,
diff --git a/bolt/lib/Core/BinarySection.cpp b/bolt/lib/Core/BinarySection.cpp
index e803d17021f8b..a8620ba83ebfb 100644
--- a/bolt/lib/Core/BinarySection.cpp
+++ b/bolt/lib/Core/BinarySection.cpp
@@ -154,7 +154,7 @@ uint64_t BinarySection::write(raw_ostream &OS) const {
   return getOutputSize();
 }
 
-void BinarySection::flushPendingRelocations(raw_pwrite_stream &OS,
+void BinarySection::flushPendingRelocations(raw_fd_ostream &OS,
                                             SymbolResolverFuncTy Resolver) {
   if (PendingRelocations.empty() && Patches.empty())
     return;
@@ -174,8 +174,8 @@ void BinarySection::flushPendingRelocations(raw_pwrite_stream &OS,
              << "  offset: 0x" << Twine::utohexstr(SectionFileOffset) << '\n');
 
   for (BinaryPatch &Patch : Patches)
-    OS.pwrite(Patch.Bytes.data(), Patch.Bytes.size(),
-              SectionFileOffset + Patch.Offset);
+    safePWrite(OS, Patch.Bytes.data(), Patch.Bytes.size(),
+               SectionFileOffset + Patch.Offset);
 
   uint64_t SkippedPendingRelocations = 0;
   for (Relocation &Reloc : PendingRelocations) {
@@ -194,9 +194,9 @@ void BinarySection::flushPendingRelocations(raw_pwrite_stream &OS,
     Value = Relocation::encodeValue(Reloc.Type, Value,
                                     SectionAddress + Reloc.Offset);
 
-    OS.pwrite(reinterpret_cast<const char *>(&Value),
-              Relocation::getSizeForType(Reloc.Type),
-              SectionFileOffset + Reloc.Offset);
+    safePWrite(OS, reinterpret_cast<const char *>(&Value),
+               Relocation::getSizeForType(Reloc.Type),
+               SectionFileOffset + Reloc.Offset);
 
     LLVM_DEBUG(
         dbgs() << "BOLT-DEBUG: writing value 0x" << Twine::utohexstr(Value)
diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp
index 17f726ae13945..855ae437f0399 100644
--- a/bolt/lib/Rewrite/MachORewriteInstance.cpp
+++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp
@@ -483,7 +483,7 @@ void MachORewriteInstance::emitAndLink() {
 }
 
 void MachORewriteInstance::writeInstrumentationSection(StringRef SectionName,
-                                                       raw_pwrite_stream &OS) {
+                                                       raw_fd_ostream &OS) {
   if (!opts::Instrument)
     return;
   ErrorOr<BinarySection &> Section = BC->getUniqueSectionByName(SectionName);
@@ -497,8 +497,8 @@ void MachORewriteInstance::writeInstrumentationSection(StringRef SectionName,
          "Section input offset cannot be zero");
   assert(Section->getAllocAddress() && "Section alloc address cannot be zero");
   assert(Section->getOutputSize() && "Section output size cannot be zero");
-  OS.pwrite(reinterpret_cast<char *>(Section->getAllocAddress()),
-            Section->getOutputSize(), Section->getInputFileOffset());
+  safePWrite(OS, reinterpret_cast<char *>(Section->getAllocAddress()),
+             Section->getOutputSize(), Section->getInputFileOffset());
 }
 
 void MachORewriteInstance::rewriteFile() {
@@ -518,13 +518,13 @@ void MachORewriteInstance::rewriteFile() {
       continue;
     if (opts::Verbosity >= 2)
       outs() << "BOLT: rewriting function \"" << Function << "\"\n";
-    OS.pwrite(reinterpret_cast<char *>(Function.getImageAddress()),
-              Function.getImageSize(), Function.getFileOffset());
+    safePWrite(OS, reinterpret_cast<char *>(Function.getImageAddress()),
+               Function.getImageSize(), Function.getFileOffset());
   }
 
   for (const BinaryFunction *Function : BC->getInjectedBinaryFunctions()) {
-    OS.pwrite(reinterpret_cast<char *>(Function->getImageAddress()),
-              Function->getImageSize(), Function->getFileOffset());
+    safePWrite(OS, reinterpret_cast<char *>(Function->getImageAddress()),
+               Function->getImageSize(), Function->getFileOffset());
   }
 
   writeInstrumentationSection("__counters", OS);
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index a6178bfff0ec8..9efae9d236f5f 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -5141,7 +5141,7 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *File) {
   NewEhdr.e_shoff = SHTOffset;
   NewEhdr.e_shnum = OutputSections.size();
   NewEhdr.e_shstrndx = NewSectionIndex[NewEhdr.e_shstrndx];
-  OS.pwrite(reinterpret_cast<const char *>(&NewEhdr), sizeof(NewEhdr), 0);
+  safePWrite(OS, reinterpret_cast<const char *>(&NewEhdr), sizeof(NewEhdr), 0);
 }
 
 template <typename ELFT, typename WriteFuncTy, typename StrTabFuncTy>
@@ -5619,25 +5619,14 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
   assert((DynSymSection || BC->IsStaticExecutable) &&
          "dynamic symbol table expected");
   if (DynSymSection) {
-    uint64_t SavedPos = Out->os().tell();
-    uint64_t RequiredPos = DynSymSection->sh_offset + DynSymSection->sh_size;
-    if (SavedPos < RequiredPos)
-      Out->os().seek(RequiredPos);
-
     updateELFSymbolTable(
         File,
-        /*IsDynSym=*/true,
-        *DynSymSection,
-        NewSectionIndex,
+        /*IsDynSym=*/true, *DynSymSection, NewSectionIndex,
         [&](size_t Offset, const ELFSymTy &Sym) {
-          Out->os().pwrite(reinterpret_cast<const char *>(&Sym),
-                           sizeof(ELFSymTy),
-                           DynSymSection->sh_offset + Offset);
+          safePWrite(Out->os(), reinterpret_cast<const char *>(&Sym),
+                     sizeof(ELFSymTy), DynSymSection->sh_offset + Offset);
         },
         [](StringRef) -> size_t { return 0; });
-
-    if (SavedPos < RequiredPos)
-      Out->os().seek(SavedPos);
   }
 
   if (opts::RemoveSymtab)
@@ -5721,7 +5710,7 @@ void RewriteInstance::patchELFAllocatableRelrSection(
     if (!Addend)
       return;
 
-    OS.pwrite(reinterpret_cast<const char *>(&Addend), PSize, FileOffset);
+    safePWrite(OS, reinterpret_cast<const char *>(&Addend), PSize, FileOffset);
   };
 
   // Fill new relative relocation offsets set
@@ -5759,8 +5748,8 @@ void RewriteInstance::patchELFAllocatableRelrSection(
       exit(1);
     }
 
-    OS.pwrite(reinterpret_cast<const char *>(&Value), DynamicRelrEntrySize,
-              RelrDynOffset);
+    safePWrite(OS, reinterpret_cast<const char *>(&Value), DynamicRelrEntrySize,
+               RelrDynOffset);
     RelrDynOffset += DynamicRelrEntrySize;
   };
 
@@ -5822,7 +5811,7 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
   DynamicRelativeRelocationsCount = 0;
 
   auto writeRela = [&OS](const Elf_Rela *RelA, uint64_t &Offset) {
-    OS.pwrite(reinterpret_cast<const char *>(RelA), sizeof(*RelA), Offset);
+    safePWrite(OS, reinterpret_cast<const char *>(RelA), sizeof(*RelA), Offset);
     Offset += sizeof(*RelA);
   };
 
@@ -5935,9 +5924,9 @@ void RewriteInstance::patchELFGOT(ELFObjectFile<ELFT> *File) {
       LLVM_DEBUG(dbgs() << "BOLT-DEBUG: patching GOT entry 0x"
                         << Twine::utohexstr(*GOTEntry) << " with 0x"
                         << Twine::utohexstr(NewAddress) << '\n');
-      OS.pwrite(reinterpret_cast<const char *>(&NewAddress), sizeof(NewAddress),
-                reinterpret_cast<const char *>(GOTEntry) -
-                    File->getData().data());
+      safePWrite(
+          OS, reinterpret_cast<const char *>(&NewAddress), sizeof(NewAddress),
+          reinterpret_cast<const char *>(GOTEntry) - File->getData().data());
     }
   }
 }
@@ -6029,8 +6018,8 @@ void RewriteInstance::patchELFDynamic(ELFObjectFile<ELFT> *File) {
       break;
     }
     if (ShouldPatch)
-      OS.pwrite(reinterpret_cast<const char *>(&NewDE), sizeof(NewDE),
-                DynamicOffset + (&Dyn - DTB) * sizeof(Dyn));
+      safePWrite(OS, reinterpret_cast<const char *>(&NewDE), sizeof(NewDE),
+                 DynamicOffset + (&Dyn - DTB) * sizeof(Dyn));
   }
 
   if (BC->RequiresZNow && !ZNowSet) {
@@ -6232,8 +6221,8 @@ void RewriteInstance::rewriteFunctionsInPlace(raw_fd_ostream &OS) {
     if (opts::Verbosity >= 2)
       BC->outs() << "BOLT: rewriting function \"" << *Function << "\"\n";
 
-    OS.pwrite(reinterpret_cast<char *>(Function->getImageAddress()),
-              Function->getImageSize(), Function->getFileOffset());
+    safePWrite(OS, reinterpret_cast<char *>(Function->getImageAddress()),
+               Function->getImageSize(), Function->getFileOffset());
 
     // Write nops at the end of the function.
     if (Function->getMaxSize() != std::numeric_limits<uint64_t>::max()) {
@@ -6256,8 +6245,8 @@ void RewriteInstance::rewriteFunctionsInPlace(raw_fd_ostream &OS) {
 
     for (const FunctionFragment &FF :
          Function->getLayout().getSplitFragments()) {
-      OS.pwrite(reinterpret_cast<char *>(FF.getImageAddress()),
-                FF.getImageSize(), FF.getFileOffset());
+      safePWrite(OS,reinterpret_cast<char *>(FF.getImageAddress()),
+                 FF.getImageSize(), FF.getFileOffset());
     }
   }
 
diff --git a/bolt/lib/Utils/Utils.cpp b/bolt/lib/Utils/Utils.cpp
index ecc2f1010a985..a9c8405d7f90b 100644
--- a/bolt/lib/Utils/Utils.cpp
+++ b/bolt/lib/Utils/Utils.cpp
@@ -97,6 +97,28 @@ std::optional<uint8_t> readDWARFExpressionTargetReg(StringRef ExprBytes) {
   return Reg;
 }
 
+void safePWrite(raw_fd_ostream &OS, const char *Src, size_t Size,
+                uint64_t Offset) {
+  if (Size == 0)
+    return;
+
+  const uint64_t SavedPos = OS.tell();
+  const uint64_t RequiredPos = Offset + Size;
+  const bool Extended = SavedPos < RequiredPos;
+
+  // raw_pwrite_stream::pwrite() expects the stream to be large enough
+  // to cover the write. If the target offset exceeds the current stream
+  // position, we must extend the stream by seeking to the required position
+  // first to avoid failures.
+  if (Extended)
+    OS.seek(RequiredPos);
+
+  OS.pwrite(Src, Size, Offset);
+
+  if (Extended)
+    OS.seek(SavedPos);
+}
+
 } // namespace bolt
 
 bool operator==(const llvm::MCCFIInstruction &L,
diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp
index d7374b323c916..1713b56938391 100644
--- a/bolt/unittests/Core/BinaryContext.cpp
+++ b/bolt/unittests/Core/BinaryContext.cpp
@@ -10,6 +10,7 @@
 #include "bolt/Utils/CommandLineOpts.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/TargetSelect.h"
 #include "gtest/gtest.h"
 
@@ -104,18 +105,23 @@ TEST_P(BinaryContextTester, FlushPendingRelocCALL26) {
   BS.addPendingRelocation(
       Relocation{12, RelSymbol2, ELF::R_AARCH64_CALL26, 0, 0});
 
-  SmallVector<char> Vect(DataSize);
-  raw_svector_ostream OS(Vect);
-
+  SmallString<64> TempPath;
+  int FD;
+  sys::fs::createTemporaryFile("bolt-test-call26", "bin", FD, TempPath);
+  raw_fd_ostream OS(FD, true);
   BS.flushPendingRelocations(OS, [&](const MCSymbol *S) {
     return S == RelSymbol1 ? 4 : S == RelSymbol2 ? 16 : 0;
   });
+  auto MBOrErr = MemoryBuffer::getFile(TempPath);
+  ASSERT_TRUE(MBOrErr);
+  const char *Vect = MBOrErr.get()->getBufferStart();
 
   const uint8_t Func1Call[4] = {255, 255, 255, 151};
   const uint8_t Func2Call[4] = {1, 0, 0, 148};
 
   EXPECT_FALSE(memcmp(Func1Call, &Vect[8], 4)) << "Wrong backward call value\n";
   EXPECT_FALSE(memcmp(Func2Call, &Vect[12], 4)) << "Wrong forward call value\n";
+  sys::fs::remove(TempPath);
 }
 
 TEST_P(BinaryContextTester, FlushPendingRelocJUMP26) {
@@ -146,12 +152,16 @@ TEST_P(BinaryContextTester, FlushPendingRelocJUMP26) {
   BS.addPendingRelocation(
       Relocation{12, RelSymbol2, ELF::R_AARCH64_JUMP26, 0, 0});
 
-  SmallVector<char> Vect(Size);
-  raw_svector_ostream OS(Vect);
-
+  SmallString<64> TempPath;
+  int FD;
+  sys::fs::createTemporaryFile("bolt-test-jump26", "bin", FD, TempPath);
+  raw_fd_ostream OS(FD, true);
   BS.flushPendingRelocations(OS, [&](const MCSymbol *S) {
     return S == RelSymbol1 ? 4 : S == RelSymbol2 ? 16 : 0;
   });
+  auto MBOrErr = MemoryBuffer::getFile(TempPath);
+  ASSERT_TRUE(MBOrErr);
+  const char *Vect = MBOrErr.get()->getBufferStart();
 
   const uint8_t Func1Call[4] = {255, 255, 255, 23};
   const uint8_t Func2Call[4] = {1, 0, 0, 20};
@@ -160,6 +170,7 @@ TEST_P(BinaryContextTester, FlushPendingRelocJUMP26) {
       << "Wrong backward branch value\n";
   EXPECT_FALSE(memcmp(Func2Call, &Vect[12], 4))
       << "Wrong forward branch value\n";
+  sys::fs::remove(TempPath);
 }
 
 TEST_P(BinaryContextTester,
@@ -182,15 +193,17 @@ TEST_P(BinaryContextTester,
   Reloc.setOptional();
   BS.addPendingRelocation(Reloc);
 
-  SmallVector<char> Vect;
-  raw_svector_ostream OS(Vect);
-
+  SmallString<64> TempPath;
+  int FD;
+  sys::fs::createTemporaryFile("bolt-test-outofrange", "bin", FD, TempPath);
+  raw_fd_ostream OS(FD, true);
   // Resolve relocation symbol to a high value so encoding will be out of range.
   BS.flushPendingRelocations(OS, [&](const MCSymbol *S) { return 0x800000F; });
   outs().flush();
   std::string CapturedStdOut = testing::internal::GetCapturedStdout();
   EXPECT_EQ(CapturedStdOut,
             "BOLT-INFO: skipped 1 out-of-range optional relocations\n");
+  sys::fs::remove(TempPath);
 }
 
 #endif



More information about the llvm-commits mailing list