[llvm] [yaml2obj] Apply output size limit to COFF (PR #209695)
Haohai Wen via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 01:47:31 PDT 2026
https://github.com/HaohaiWen updated https://github.com/llvm/llvm-project/pull/209695
>From f4b4f650abe4b58b3241296a5235f2f617a2ba43 Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Wed, 15 Jul 2026 15:41:48 +0800
Subject: [PATCH 1/4] [yaml2obj] Apply output size limit to COFF
Route the yaml2obj max-size setting through the COFF emitter and
buffer COFF output with ContiguousBlobAccumulator. This rejects
oversized YAML descriptions consistently with ELF.
---
llvm/include/llvm/ObjectYAML/COFFYAML.h | 6 +-
llvm/include/llvm/ObjectYAML/yaml2obj.h | 2 +-
llvm/lib/ObjectYAML/COFFEmitter.cpp | 265 +++++++++---------
llvm/lib/ObjectYAML/yaml2obj.cpp | 2 +-
.../tools/yaml2obj/COFF/output-limit.yaml | 22 ++
llvm/tools/yaml2obj/yaml2obj.cpp | 9 +-
6 files changed, 161 insertions(+), 145 deletions(-)
create mode 100644 llvm/test/tools/yaml2obj/COFF/output-limit.yaml
diff --git a/llvm/include/llvm/ObjectYAML/COFFYAML.h b/llvm/include/llvm/ObjectYAML/COFFYAML.h
index 78f48914a6d69..dcac51ab4c845 100644
--- a/llvm/include/llvm/ObjectYAML/COFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/COFFYAML.h
@@ -26,6 +26,10 @@
namespace llvm {
+namespace yaml {
+class ContiguousBlobAccumulator;
+}
+
namespace COFF {
inline Characteristics operator|(Characteristics a, Characteristics b) {
@@ -74,7 +78,7 @@ struct SectionDataEntry {
std::optional<object::coff_load_configuration64> LoadConfig64;
LLVM_ABI size_t size() const;
- LLVM_ABI void writeAsBinary(raw_ostream &OS) const;
+ LLVM_ABI void writeAsBinary(yaml::ContiguousBlobAccumulator &CBA) const;
};
struct Section {
diff --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h
index 4c9084b790507..a797155357fa4 100644
--- a/llvm/include/llvm/ObjectYAML/yaml2obj.h
+++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h
@@ -70,7 +70,7 @@ using ErrorHandler = llvm::function_ref<void(const Twine &Msg)>;
LLVM_ABI bool yaml2archive(ArchYAML::Archive &Doc, raw_ostream &Out,
ErrorHandler EH);
LLVM_ABI bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out,
- ErrorHandler EH);
+ ErrorHandler EH, uint64_t MaxSize);
LLVM_ABI bool yaml2goff(GOFFYAML::Object &Doc, raw_ostream &Out,
ErrorHandler EH);
LLVM_ABI bool yaml2elf(ELFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH,
diff --git a/llvm/lib/ObjectYAML/COFFEmitter.cpp b/llvm/lib/ObjectYAML/COFFEmitter.cpp
index 8ba9e44c15385..ec61b027ab96f 100644
--- a/llvm/lib/ObjectYAML/COFFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/COFFEmitter.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/ObjectYAML/ContiguousBlobAccumulator.h"
#include "llvm/ObjectYAML/ObjectYAML.h"
#include "llvm/ObjectYAML/yaml2obj.h"
#include "llvm/Support/BinaryStreamWriter.h"
@@ -25,9 +26,12 @@
#include <vector>
using namespace llvm;
+using llvm::yaml::ContiguousBlobAccumulator;
namespace {
+constexpr auto LittleEndian = llvm::endianness::little;
+
/// This parses a yaml stream that represents a COFF object file.
/// See docs/yaml2obj for the yaml scheema.
struct COFFParser {
@@ -299,40 +303,6 @@ static bool layoutCOFF(COFFParser &CP) {
return true;
}
-template <typename value_type> struct binary_le_impl {
- value_type Value;
- binary_le_impl(value_type V) : Value(V) {}
-};
-
-template <typename value_type>
-raw_ostream &operator<<(raw_ostream &OS,
- const binary_le_impl<value_type> &BLE) {
- char Buffer[sizeof(BLE.Value)];
- support::endian::write<value_type, llvm::endianness::little>(Buffer,
- BLE.Value);
- OS.write(Buffer, sizeof(BLE.Value));
- return OS;
-}
-
-template <typename value_type>
-binary_le_impl<value_type> binary_le(value_type V) {
- return binary_le_impl<value_type>(V);
-}
-
-template <size_t NumBytes> struct zeros_impl {};
-
-template <size_t NumBytes>
-raw_ostream &operator<<(raw_ostream &OS, const zeros_impl<NumBytes> &) {
- char Buffer[NumBytes];
- memset(Buffer, 0, sizeof(Buffer));
- OS.write(Buffer, sizeof(Buffer));
- return OS;
-}
-
-template <typename T> zeros_impl<sizeof(T)> zeros(const T &) {
- return zeros_impl<sizeof(T)>();
-}
-
template <typename T>
static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic,
T Header) {
@@ -388,7 +358,7 @@ static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic,
return BaseOfData;
}
-static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
+static bool writeCOFF(COFFParser &CP, ContiguousBlobAccumulator &CBA) {
if (CP.isPE()) {
// PE files start with a DOS stub.
object::dos_header DH;
@@ -405,45 +375,47 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
DH.AddressOfNewExeHeader = DOSStubSize;
// Write out our DOS stub.
- OS.write(reinterpret_cast<char *>(&DH), sizeof(DH));
+ CBA.write(reinterpret_cast<const char *>(&DH), sizeof(DH));
// Write padding until we reach the position of where our PE signature
// should live.
- OS.write_zeros(DOSStubSize - sizeof(DH));
+ CBA.writeZeros(DOSStubSize - sizeof(DH));
// Write out the PE signature.
- OS.write(COFF::PEMagic, sizeof(COFF::PEMagic));
+ CBA.write(COFF::PEMagic, sizeof(COFF::PEMagic));
}
if (CP.useBigObj()) {
- OS << binary_le(static_cast<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN))
- << binary_le(static_cast<uint16_t>(0xffff))
- << binary_le(
- static_cast<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion))
- << binary_le(CP.Obj.Header.Machine)
- << binary_le(CP.Obj.Header.TimeDateStamp);
- OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic));
- OS << zeros(uint32_t(0)) << zeros(uint32_t(0)) << zeros(uint32_t(0))
- << zeros(uint32_t(0)) << binary_le(CP.Obj.Header.NumberOfSections)
- << binary_le(CP.Obj.Header.PointerToSymbolTable)
- << binary_le(CP.Obj.Header.NumberOfSymbols);
+ CBA.write(static_cast<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN),
+ LittleEndian);
+ CBA.write(static_cast<uint16_t>(0xffff), LittleEndian);
+ CBA.write(static_cast<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion),
+ LittleEndian);
+ CBA.write(CP.Obj.Header.Machine, LittleEndian);
+ CBA.write(CP.Obj.Header.TimeDateStamp, LittleEndian);
+ CBA.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic));
+ CBA.writeZeros(4 * sizeof(uint32_t));
+ CBA.write(CP.Obj.Header.NumberOfSections, LittleEndian);
+ CBA.write(CP.Obj.Header.PointerToSymbolTable, LittleEndian);
+ CBA.write(CP.Obj.Header.NumberOfSymbols, LittleEndian);
} else {
- OS << binary_le(CP.Obj.Header.Machine)
- << binary_le(static_cast<int16_t>(CP.Obj.Header.NumberOfSections))
- << binary_le(CP.Obj.Header.TimeDateStamp)
- << binary_le(CP.Obj.Header.PointerToSymbolTable)
- << binary_le(CP.Obj.Header.NumberOfSymbols)
- << binary_le(CP.Obj.Header.SizeOfOptionalHeader)
- << binary_le(CP.Obj.Header.Characteristics);
+ CBA.write(CP.Obj.Header.Machine, LittleEndian);
+ CBA.write(static_cast<int16_t>(CP.Obj.Header.NumberOfSections),
+ LittleEndian);
+ CBA.write(CP.Obj.Header.TimeDateStamp, LittleEndian);
+ CBA.write(CP.Obj.Header.PointerToSymbolTable, LittleEndian);
+ CBA.write(CP.Obj.Header.NumberOfSymbols, LittleEndian);
+ CBA.write(CP.Obj.Header.SizeOfOptionalHeader, LittleEndian);
+ CBA.write(CP.Obj.Header.Characteristics, LittleEndian);
}
if (CP.isPE()) {
if (CP.is64Bit()) {
object::pe32plus_header PEH;
initializeOptionalHeader(CP, COFF::PE32Header::PE32_PLUS, &PEH);
- OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
+ CBA.write(reinterpret_cast<const char *>(&PEH), sizeof(PEH));
} else {
object::pe32_header PEH;
uint32_t BaseOfData =
initializeOptionalHeader(CP, COFF::PE32Header::PE32, &PEH);
PEH.BaseOfData = BaseOfData;
- OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
+ CBA.write(reinterpret_cast<const char *>(&PEH), sizeof(PEH));
}
for (uint32_t I = 0; I < CP.Obj.OptionalHeader->Header.NumberOfRvaAndSize;
++I) {
@@ -451,30 +423,29 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
CP.Obj.OptionalHeader->DataDirectories;
uint32_t NumDataDir = std::size(CP.Obj.OptionalHeader->DataDirectories);
if (I >= NumDataDir || !DataDirectories[I]) {
- OS << zeros(uint32_t(0));
- OS << zeros(uint32_t(0));
+ CBA.writeZeros(2 * sizeof(uint32_t));
} else {
- OS << binary_le(DataDirectories[I]->RelativeVirtualAddress);
- OS << binary_le(DataDirectories[I]->Size);
+ CBA.write(DataDirectories[I]->RelativeVirtualAddress, LittleEndian);
+ CBA.write(DataDirectories[I]->Size, LittleEndian);
}
}
}
- assert(OS.tell() == CP.SectionTableStart);
+ assert(CBA.getOffset() == CP.SectionTableStart);
// Output section table.
for (const COFFYAML::Section &S : CP.Obj.Sections) {
- OS.write(S.Header.Name, COFF::NameSize);
- OS << binary_le(S.Header.VirtualSize)
- << binary_le(S.Header.VirtualAddress)
- << binary_le(S.Header.SizeOfRawData)
- << binary_le(S.Header.PointerToRawData)
- << binary_le(S.Header.PointerToRelocations)
- << binary_le(S.Header.PointerToLineNumbers)
- << binary_le(S.Header.NumberOfRelocations)
- << binary_le(S.Header.NumberOfLineNumbers)
- << binary_le(S.Header.Characteristics);
+ CBA.write(S.Header.Name, COFF::NameSize);
+ CBA.write(S.Header.VirtualSize, LittleEndian);
+ CBA.write(S.Header.VirtualAddress, LittleEndian);
+ CBA.write(S.Header.SizeOfRawData, LittleEndian);
+ CBA.write(S.Header.PointerToRawData, LittleEndian);
+ CBA.write(S.Header.PointerToRelocations, LittleEndian);
+ CBA.write(S.Header.PointerToLineNumbers, LittleEndian);
+ CBA.write(S.Header.NumberOfRelocations, LittleEndian);
+ CBA.write(S.Header.NumberOfLineNumbers, LittleEndian);
+ CBA.write(S.Header.Characteristics, LittleEndian);
}
- assert(OS.tell() == CP.SectionTableStart + CP.SectionTableSize);
+ assert(CBA.getOffset() == CP.SectionTableStart + CP.SectionTableSize);
unsigned CurSymbol = 0;
StringMap<unsigned> SymbolTableIndexMap;
@@ -487,18 +458,21 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
for (const COFFYAML::Section &S : CP.Obj.Sections) {
if (S.Header.SizeOfRawData == 0 || S.Header.PointerToRawData == 0)
continue;
- assert(S.Header.PointerToRawData >= OS.tell());
- OS.write_zeros(S.Header.PointerToRawData - OS.tell());
+ assert(S.Header.PointerToRawData >= CBA.getOffset());
+ CBA.writeZeros(S.Header.PointerToRawData - CBA.getOffset());
for (auto E : S.StructuredData)
- E.writeAsBinary(OS);
- S.SectionData.writeAsBinary(OS);
- assert(S.Header.SizeOfRawData >= S.SectionData.binary_size());
- OS.write_zeros(S.Header.PointerToRawData + S.Header.SizeOfRawData -
- OS.tell());
- if (S.Header.Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL)
- OS << binary_le<uint32_t>(/*VirtualAddress=*/ S.Relocations.size() + 1)
- << binary_le<uint32_t>(/*SymbolTableIndex=*/ 0)
- << binary_le<uint16_t>(/*Type=*/ 0);
+ E.writeAsBinary(CBA);
+ CBA.writeAsBinary(S.SectionData);
+ assert(S.Header.PointerToRawData + S.Header.SizeOfRawData >=
+ CBA.getOffset());
+ CBA.writeZeros(S.Header.PointerToRawData + S.Header.SizeOfRawData -
+ CBA.getOffset());
+ if (S.Header.Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL) {
+ CBA.write<uint32_t>(/*VirtualAddress=*/S.Relocations.size() + 1,
+ LittleEndian);
+ CBA.write<uint32_t>(/*SymbolTableIndex=*/0, LittleEndian);
+ CBA.write<uint16_t>(/*Type=*/0, LittleEndian);
+ }
for (const COFFYAML::Relocation &R : S.Relocations) {
uint32_t SymbolTableIndex;
if (R.SymbolTableIndex) {
@@ -509,46 +483,47 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
} else {
SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
}
- OS << binary_le(R.VirtualAddress) << binary_le(SymbolTableIndex)
- << binary_le(R.Type);
+ CBA.write(R.VirtualAddress, LittleEndian);
+ CBA.write(SymbolTableIndex, LittleEndian);
+ CBA.write(R.Type, LittleEndian);
}
}
// Output symbol table.
-
for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(),
e = CP.Obj.Symbols.end();
i != e; ++i) {
- OS.write(i->Header.Name, COFF::NameSize);
- OS << binary_le(i->Header.Value);
+ CBA.write(i->Header.Name, COFF::NameSize);
+ CBA.write(i->Header.Value, LittleEndian);
if (CP.useBigObj())
- OS << binary_le(i->Header.SectionNumber);
+ CBA.write(i->Header.SectionNumber, LittleEndian);
else
- OS << binary_le(static_cast<int16_t>(i->Header.SectionNumber));
- OS << binary_le(i->Header.Type) << binary_le(i->Header.StorageClass)
- << binary_le(i->Header.NumberOfAuxSymbols);
+ CBA.write(static_cast<int16_t>(i->Header.SectionNumber), LittleEndian);
+ CBA.write(i->Header.Type, LittleEndian);
+ CBA.write(i->Header.StorageClass, LittleEndian);
+ CBA.write(i->Header.NumberOfAuxSymbols, LittleEndian);
if (i->FunctionDefinition) {
- OS << binary_le(i->FunctionDefinition->TagIndex)
- << binary_le(i->FunctionDefinition->TotalSize)
- << binary_le(i->FunctionDefinition->PointerToLinenumber)
- << binary_le(i->FunctionDefinition->PointerToNextFunction)
- << zeros(i->FunctionDefinition->unused);
- OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
+ CBA.write(i->FunctionDefinition->TagIndex, LittleEndian);
+ CBA.write(i->FunctionDefinition->TotalSize, LittleEndian);
+ CBA.write(i->FunctionDefinition->PointerToLinenumber, LittleEndian);
+ CBA.write(i->FunctionDefinition->PointerToNextFunction, LittleEndian);
+ CBA.writeZeros(sizeof(i->FunctionDefinition->unused));
+ CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
}
if (i->bfAndefSymbol) {
- OS << zeros(i->bfAndefSymbol->unused1)
- << binary_le(i->bfAndefSymbol->Linenumber)
- << zeros(i->bfAndefSymbol->unused2)
- << binary_le(i->bfAndefSymbol->PointerToNextFunction)
- << zeros(i->bfAndefSymbol->unused3);
- OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
+ CBA.writeZeros(sizeof(i->bfAndefSymbol->unused1));
+ CBA.write(i->bfAndefSymbol->Linenumber, LittleEndian);
+ CBA.writeZeros(sizeof(i->bfAndefSymbol->unused2));
+ CBA.write(i->bfAndefSymbol->PointerToNextFunction, LittleEndian);
+ CBA.writeZeros(sizeof(i->bfAndefSymbol->unused3));
+ CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
}
if (i->WeakExternal) {
- OS << binary_le(i->WeakExternal->TagIndex)
- << binary_le(i->WeakExternal->Characteristics)
- << zeros(i->WeakExternal->unused);
- OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
+ CBA.write(i->WeakExternal->TagIndex, LittleEndian);
+ CBA.write(i->WeakExternal->Characteristics, LittleEndian);
+ CBA.writeZeros(sizeof(i->WeakExternal->unused));
+ CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
}
if (!i->File.empty()) {
unsigned SymbolSize = CP.getSymbolSize();
@@ -556,31 +531,34 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
(i->File.size() + SymbolSize - 1) / SymbolSize;
uint32_t NumberOfAuxBytes = NumberOfAuxRecords * SymbolSize;
uint32_t NumZeros = NumberOfAuxBytes - i->File.size();
- OS.write(i->File.data(), i->File.size());
- OS.write_zeros(NumZeros);
+ CBA.write(i->File.data(), i->File.size());
+ CBA.writeZeros(NumZeros);
}
if (i->SectionDefinition) {
- OS << binary_le(i->SectionDefinition->Length)
- << binary_le(i->SectionDefinition->NumberOfRelocations)
- << binary_le(i->SectionDefinition->NumberOfLinenumbers)
- << binary_le(i->SectionDefinition->CheckSum)
- << binary_le(static_cast<int16_t>(i->SectionDefinition->Number))
- << binary_le(i->SectionDefinition->Selection)
- << zeros(i->SectionDefinition->unused)
- << binary_le(static_cast<int16_t>(i->SectionDefinition->Number >> 16));
- OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
+ CBA.write(i->SectionDefinition->Length, LittleEndian);
+ CBA.write(i->SectionDefinition->NumberOfRelocations, LittleEndian);
+ CBA.write(i->SectionDefinition->NumberOfLinenumbers, LittleEndian);
+ CBA.write(i->SectionDefinition->CheckSum, LittleEndian);
+ CBA.write(static_cast<int16_t>(i->SectionDefinition->Number),
+ LittleEndian);
+ CBA.write(i->SectionDefinition->Selection, LittleEndian);
+ CBA.writeZeros(sizeof(i->SectionDefinition->unused));
+ CBA.write(static_cast<int16_t>(i->SectionDefinition->Number >> 16),
+ LittleEndian);
+ CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
}
if (i->CLRToken) {
- OS << binary_le(i->CLRToken->AuxType) << zeros(i->CLRToken->unused1)
- << binary_le(i->CLRToken->SymbolTableIndex)
- << zeros(i->CLRToken->unused2);
- OS.write_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
+ CBA.write(i->CLRToken->AuxType, LittleEndian);
+ CBA.writeZeros(sizeof(i->CLRToken->unused1));
+ CBA.write(i->CLRToken->SymbolTableIndex, LittleEndian);
+ CBA.writeZeros(sizeof(i->CLRToken->unused2));
+ CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
}
}
// Output string table.
if (CP.Obj.Header.PointerToSymbolTable)
- OS.write(&CP.StringTable[0], CP.StringTable.size());
+ CBA.write(&CP.StringTable[0], CP.StringTable.size());
return true;
}
@@ -595,28 +573,30 @@ size_t COFFYAML::SectionDataEntry::size() const {
return Size;
}
-template <typename T> static void writeLoadConfig(T &S, raw_ostream &OS) {
- OS.write(reinterpret_cast<const char *>(&S),
- std::min(sizeof(S), static_cast<size_t>(S.Size)));
+template <typename T>
+static void writeLoadConfig(T &S, ContiguousBlobAccumulator &CBA) {
+ CBA.write(reinterpret_cast<const char *>(&S),
+ std::min(sizeof(S), static_cast<size_t>(S.Size)));
if (sizeof(S) < S.Size)
- OS.write_zeros(S.Size - sizeof(S));
+ CBA.writeZeros(S.Size - sizeof(S));
}
-void COFFYAML::SectionDataEntry::writeAsBinary(raw_ostream &OS) const {
+void COFFYAML::SectionDataEntry::writeAsBinary(
+ ContiguousBlobAccumulator &CBA) const {
if (UInt32)
- OS << binary_le(*UInt32);
- Binary.writeAsBinary(OS);
+ CBA.write(*UInt32, LittleEndian);
+ CBA.writeAsBinary(Binary);
if (LoadConfig32)
- writeLoadConfig(*LoadConfig32, OS);
+ writeLoadConfig(*LoadConfig32, CBA);
if (LoadConfig64)
- writeLoadConfig(*LoadConfig64, OS);
+ writeLoadConfig(*LoadConfig64, CBA);
}
namespace llvm {
namespace yaml {
bool yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out,
- ErrorHandler ErrHandler) {
+ ErrorHandler ErrHandler, uint64_t MaxSize) {
COFFParser CP(Doc, ErrHandler);
if (!CP.parse()) {
ErrHandler("failed to parse YAML file");
@@ -632,10 +612,21 @@ bool yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out,
ErrHandler("failed to layout COFF file");
return false;
}
- if (!writeCOFF(CP, Out)) {
+
+ // Limit the output size to guard against a runaway YAML description.
+ ContiguousBlobAccumulator CBA(/*BaseOffset=*/0, MaxSize);
+ if (!writeCOFF(CP, CBA)) {
ErrHandler("failed to write COFF file");
return false;
}
+ if (Error E = CBA.takeLimitError()) {
+ consumeError(std::move(E));
+ ErrHandler("the desired output size is greater than permitted. Use the "
+ "--max-size option to change the limit");
+ return false;
+ }
+
+ CBA.writeBlobToStream(Out);
return true;
}
diff --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp
index 8390233e24244..469a6f96cdfa1 100644
--- a/llvm/lib/ObjectYAML/yaml2obj.cpp
+++ b/llvm/lib/ObjectYAML/yaml2obj.cpp
@@ -36,7 +36,7 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
if (Doc.Elf)
return yaml2elf(*Doc.Elf, Out, ErrHandler, MaxSize);
if (Doc.Coff)
- return yaml2coff(*Doc.Coff, Out, ErrHandler);
+ return yaml2coff(*Doc.Coff, Out, ErrHandler, MaxSize);
if (Doc.Goff)
return yaml2goff(*Doc.Goff, Out, ErrHandler);
if (Doc.MachO || Doc.FatMachO)
diff --git a/llvm/test/tools/yaml2obj/COFF/output-limit.yaml b/llvm/test/tools/yaml2obj/COFF/output-limit.yaml
new file mode 100644
index 0000000000000..4e43af05dbbbc
--- /dev/null
+++ b/llvm/test/tools/yaml2obj/COFF/output-limit.yaml
@@ -0,0 +1,22 @@
+## Check the default COFF output limit and --max-size.
+## 0x9FFFC4 = 0xA00000 (10 MB) - COFF::Header16Size - COFF::SectionSize.
+# RUN: yaml2obj %s -DSIZE=0x9FFFC4 -o /dev/null
+# RUN: not yaml2obj %s -DSIZE=0xA00001 -o /dev/null 2>&1 | FileCheck %s
+# RUN: yaml2obj %s -DSIZE=0xA00001 --max-size=0 -o /dev/null
+# RUN: not yaml2obj %s -DSIZE=0xA00001 --max-size=0x100 -o /dev/null 2>&1 | \
+# RUN: FileCheck %s
+
+# CHECK: error: the desired output size is greater than permitted. Use the --max-size option to change the limit
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ StructuredData:
+ - LoadConfig:
+ Size: [[SIZE]]
+symbols: []
+...
diff --git a/llvm/tools/yaml2obj/yaml2obj.cpp b/llvm/tools/yaml2obj/yaml2obj.cpp
index 662648b599954..78744f5784cba 100644
--- a/llvm/tools/yaml2obj/yaml2obj.cpp
+++ b/llvm/tools/yaml2obj/yaml2obj.cpp
@@ -49,11 +49,10 @@ cl::opt<unsigned>
cl::desc("Read specified document from input (default = 1)"),
cl::cat(Cat));
-static cl::opt<uint64_t> MaxSize(
- "max-size", cl::init(10 * 1024 * 1024),
- cl::desc(
- "Sets the maximum allowed output size (0 means no limit) [ELF only]"),
- cl::cat(Cat));
+static cl::opt<uint64_t>
+ MaxSize("max-size", cl::init(10 * 1024 * 1024),
+ cl::desc("Sets the maximum allowed output size (0 means no limit)"),
+ cl::cat(Cat));
cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
cl::value_desc("filename"), cl::init("-"),
>From 912c2115efd4af089e3473d19b2f0f96f647c0c1 Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Wed, 15 Jul 2026 16:03:20 +0800
Subject: [PATCH 2/4] [yaml2obj] Clarify max-size format support
Mention that --max-size is currently enforced for ELF and COFF outputs only.
---
llvm/tools/yaml2obj/yaml2obj.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/tools/yaml2obj/yaml2obj.cpp b/llvm/tools/yaml2obj/yaml2obj.cpp
index 78744f5784cba..0cb3d5d61b126 100644
--- a/llvm/tools/yaml2obj/yaml2obj.cpp
+++ b/llvm/tools/yaml2obj/yaml2obj.cpp
@@ -51,7 +51,8 @@ cl::opt<unsigned>
static cl::opt<uint64_t>
MaxSize("max-size", cl::init(10 * 1024 * 1024),
- cl::desc("Sets the maximum allowed output size (0 means no limit)"),
+ cl::desc("Sets the maximum allowed output size (0 means no limit) "
+ "[ELF and COFF only]"),
cl::cat(Cat));
cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
>From 5d48ec92bc29cfc01bb3f61bc8ad019ea293d151 Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Wed, 15 Jul 2026 16:07:01 +0800
Subject: [PATCH 3/4] [yaml2obj] Use data for COFF string table writes
Use std::string::data() when accessing the COFF string table buffer instead of indexing the first element.
---
llvm/lib/ObjectYAML/COFFEmitter.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/ObjectYAML/COFFEmitter.cpp b/llvm/lib/ObjectYAML/COFFEmitter.cpp
index ec61b027ab96f..1a7315924ca5c 100644
--- a/llvm/lib/ObjectYAML/COFFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/COFFEmitter.cpp
@@ -297,7 +297,7 @@ static bool layoutCOFF(COFFParser &CP) {
else
CP.Obj.Header.PointerToSymbolTable = 0;
- *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0]) =
+ *reinterpret_cast<support::ulittle32_t *>(CP.StringTable.data()) =
CP.StringTable.size();
return true;
@@ -558,7 +558,7 @@ static bool writeCOFF(COFFParser &CP, ContiguousBlobAccumulator &CBA) {
// Output string table.
if (CP.Obj.Header.PointerToSymbolTable)
- CBA.write(&CP.StringTable[0], CP.StringTable.size());
+ CBA.write(CP.StringTable.data(), CP.StringTable.size());
return true;
}
>From 475b3b97e9ef4c67328f775e92516fed561ac091 Mon Sep 17 00:00:00 2001
From: Haohai Wen <haohai.wen at intel.com>
Date: Wed, 15 Jul 2026 16:34:00 +0800
Subject: [PATCH 4/4] [yaml2obj] Comment COFF output limit diagnostic
---
llvm/lib/ObjectYAML/COFFEmitter.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/ObjectYAML/COFFEmitter.cpp b/llvm/lib/ObjectYAML/COFFEmitter.cpp
index 1a7315924ca5c..d2a4a3b1313d2 100644
--- a/llvm/lib/ObjectYAML/COFFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/COFFEmitter.cpp
@@ -620,6 +620,7 @@ bool yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out,
return false;
}
if (Error E = CBA.takeLimitError()) {
+ // Match ELF by reporting a custom error message instead below.
consumeError(std::move(E));
ErrHandler("the desired output size is greater than permitted. Use the "
"--max-size option to change the limit");
More information about the llvm-commits
mailing list