Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -109,8 +109,8 @@ // in the output section. The latter may be -1 if it is not assigned yet. std::vector> Offsets; - std::pair *, uintX_t> - getRangeAndSize(uintX_t Offset); + bool getRangeAndSize(uintX_t Offset, std::pair *&P, + uintX_t &End); }; // This corresponds to a SHF_MERGE section of an input file. Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -29,7 +29,8 @@ template StringRef InputSectionBase::getSectionName() const { ErrorOr Name = File->getObj().getSectionName(this->Header); - fatal(Name); + if (error(Name, "getSectionName failed")) + return ""; return *Name; } @@ -37,7 +38,8 @@ ArrayRef InputSectionBase::getSectionData() const { ErrorOr> Ret = this->File->getObj().getSectionContents(this->Header); - fatal(Ret); + if (error(Ret, "getSectionContents failed")) + return {}; return *Ret; } @@ -297,7 +299,11 @@ // identify the start of the output .eh_frame. Handle this special case. if (this->getSectionHdr()->sh_size == 0) return Offset; - std::pair *I = this->getRangeAndSize(Offset).first; + + std::pair *I; + uintX_t End; + if (!this->getRangeAndSize(Offset, I, End)) + return 0; // Returns a dummy value for a broken symbol. uintX_t Base = I->second; if (Base == uintX_t(-1)) return -1; // Not in the output @@ -317,15 +323,16 @@ } template -std::pair::uintX_t, - typename ELFFile::uintX_t> *, - typename ELFFile::uintX_t> -SplitInputSection::getRangeAndSize(uintX_t Offset) { +bool SplitInputSection::getRangeAndSize(uintX_t Offset, + std::pair *&P, + uintX_t &End) { ArrayRef D = this->getSectionData(); StringRef Data((const char *)D.data(), D.size()); uintX_t Size = Data.size(); - if (Offset >= Size) - fatal("Entry is past the end of the section"); + if (Offset >= Size) { + error("Entry is past the end of the section"); + return false; + } // Find the element this offset points to. auto I = std::upper_bound( @@ -333,18 +340,19 @@ [](const uintX_t &A, const std::pair &B) { return A < B.first; }); - uintX_t End = I == Offsets.end() ? Data.size() : I->first; + End = I == Offsets.end() ? Data.size() : I->first; --I; - return std::make_pair(&*I, End); + P = &*I; + return true; } template typename MergeInputSection::uintX_t MergeInputSection::getOffset(uintX_t Offset) { - std::pair *, uintX_t> T = - this->getRangeAndSize(Offset); - std::pair *I = T.first; - uintX_t End = T.second; + std::pair *I; + uintX_t End; + if (!this->getRangeAndSize(Offset, I, End)) + return 0; // Returns a dummy value for a broken symbol. uintX_t Start = I->first; // Compute the Addend and if the Base is cached, return. @@ -369,8 +377,9 @@ // Initialize this->Reginfo. ArrayRef D = this->getSectionData(); if (D.size() != sizeof(Elf_Mips_RegInfo)) - fatal("Invalid size of .reginfo section"); - Reginfo = reinterpret_cast *>(D.data()); + error("Invalid size of .reginfo section"); + else + Reginfo = reinterpret_cast *>(D.data()); } template Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -306,8 +306,8 @@ void addSection(InputSectionBase *S) override; private: - uint8_t getFdeEncoding(ArrayRef D); - uintX_t readEntryLength(ArrayRef D); + bool getFdeEncoding(ArrayRef D, uint8_t &Result); + bool readEntryLength(ArrayRef D, uintX_t &Result); std::vector *> Sections; std::vector> Cies; @@ -471,7 +471,7 @@ uint8_t *PCRel; }; - uintX_t getFdePc(uintX_t EhVA, const FdeData &F); + bool getFdePc(uintX_t EhVA, const FdeData &F, uintX_t &Result); EHOutputSection *Sec = nullptr; std::vector FdeList; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -749,8 +749,8 @@ // encoding given for FDEs. Return value is an offset to the initial PC value // for the FDE. template -typename EhFrameHeader::uintX_t -EhFrameHeader::getFdePc(uintX_t EhVA, const FdeData &F) { +bool EhFrameHeader::getFdePc(uintX_t EhVA, const FdeData &F, + uintX_t &Result) { const endianness E = ELFT::TargetEndianness; assert((F.Enc & 0xF0) != dwarf::DW_EH_PE_datarel); @@ -758,19 +758,25 @@ switch (F.Enc & 0xF) { case dwarf::DW_EH_PE_udata2: case dwarf::DW_EH_PE_sdata2: - return FdeOff + read16(F.PCRel); + Result = FdeOff + read16(F.PCRel); + return true; case dwarf::DW_EH_PE_udata4: case dwarf::DW_EH_PE_sdata4: - return FdeOff + read32(F.PCRel); + Result = FdeOff + read32(F.PCRel); + return true; case dwarf::DW_EH_PE_udata8: case dwarf::DW_EH_PE_sdata8: - return FdeOff + read64(F.PCRel); + Result = FdeOff + read64(F.PCRel); + return true; case dwarf::DW_EH_PE_absptr: if (sizeof(uintX_t) == 8) - return FdeOff + read64(F.PCRel); - return FdeOff + read32(F.PCRel); + Result = FdeOff + read64(F.PCRel); + else + Result = FdeOff + read32(F.PCRel); + return true; } - fatal("unknown FDE size encoding"); + error("unknown FDE size encoding"); + return false; } template void EhFrameHeader::writeTo(uint8_t *Buf) { @@ -790,8 +796,12 @@ // InitialPC -> Offset in .eh_frame, sorted by InitialPC. std::map PcToOffset; - for (const FdeData &F : FdeList) - PcToOffset[getFdePc(EhVA, F)] = F.Off; + for (const FdeData &F : FdeList) { + uintX_t PC; + if (!getFdePc(EhVA, F, PC)) + return; + PcToOffset[PC] = F.Off; + } for (auto &I : PcToOffset) { // The first four bytes are an offset to the initial PC value for the FDE. @@ -813,8 +823,9 @@ template void EhFrameHeader::addFde(uint8_t Enc, size_t Off, uint8_t *PCRel) { if (Live && (Enc & 0xF0) == dwarf::DW_EH_PE_datarel) - fatal("DW_EH_PE_datarel encoding unsupported for FDEs by .eh_frame_hdr"); - FdeList.push_back(FdeData{Enc, Off, PCRel}); + error("DW_EH_PE_datarel encoding unsupported for FDEs by .eh_frame_hdr"); + else + FdeList.push_back(FdeData{Enc, Off, PCRel}); } template void EhFrameHeader::reserveFde() { @@ -903,8 +914,10 @@ const Elf_Sym *Sym = File.getObj().getRelocationSymbol(&RI, File.getSymbolTable()); - if (!Sym) - fatal("Unsupported relocation without symbol"); + if (!Sym) { + error("Unsupported relocation without symbol"); + return 0; + } InputSectionBase *Section = File.getSection(*Sym); @@ -999,90 +1012,129 @@ : EHRegion(S, Index) {} // Read a byte and advance D by one byte. -static uint8_t readByte(ArrayRef &D) { - if (D.empty()) - fatal("corrupted or unsupported CIE information"); - uint8_t B = D.front(); +static bool readByte(ArrayRef &D, uint8_t &Result) { + if (D.empty()) { + error("corrupted or unsupported CIE information"); + return false; + } + Result = D.front(); D = D.slice(1); - return B; + return true; } -static void skipLeb128(ArrayRef &D) { +static bool skipLeb128(ArrayRef &D) { while (!D.empty()) { uint8_t Val = D.front(); D = D.slice(1); if ((Val & 0x80) == 0) - return; + return true; } - fatal("corrupted or unsupported CIE information"); + error("corrupted or unsupported CIE information"); + return false; } -template static unsigned getSizeForEncoding(unsigned Enc) { +template +static bool getSizeForEncoding(unsigned Enc, unsigned &Result) { typedef typename ELFFile::uintX_t uintX_t; switch (Enc & 0x0f) { default: - fatal("unknown FDE encoding"); + error("unknown FDE encoding"); + return false; case dwarf::DW_EH_PE_absptr: case dwarf::DW_EH_PE_signed: - return sizeof(uintX_t); + Result = sizeof(uintX_t); + return true; case dwarf::DW_EH_PE_udata2: case dwarf::DW_EH_PE_sdata2: - return 2; + Result = 2; + return true; case dwarf::DW_EH_PE_udata4: case dwarf::DW_EH_PE_sdata4: - return 4; + Result = 4; + return true; case dwarf::DW_EH_PE_udata8: case dwarf::DW_EH_PE_sdata8: - return 8; + Result = 8; + return true; } } template -uint8_t EHOutputSection::getFdeEncoding(ArrayRef D) { - auto Check = [](bool C) { - if (!C) - fatal("corrupted or unsupported CIE information"); - }; - - Check(D.size() >= 8); +bool EHOutputSection::getFdeEncoding(ArrayRef D, + uint8_t &Result) { + if (D.size() < 8) { + error("CIE too small"); + return false; + } D = D.slice(8); - uint8_t Version = readByte(D); - if (Version != 1 && Version != 3) - fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version)); + uint8_t Version; + if (!readByte(D, Version)) + return false; + if (Version != 1 && Version != 3) { + error("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version)); + return false; + } auto AugEnd = std::find(D.begin() + 1, D.end(), '\0'); - Check(AugEnd != D.end()); + if (AugEnd == D.end()) { + error("corrupted or unsupported CIE information"); + return false; + } ArrayRef AugString(D.begin(), AugEnd - D.begin()); D = D.slice(AugString.size() + 1); // Code alignment factor should always be 1 for .eh_frame. - if (readByte(D) != 1) - fatal("CIE code alignment must be 1"); + uint8_t Align; + if (!readByte(D, Align)) + return false; + if (Align != 1) { + error("CIE code alignment must be 1"); + return false; + } + // Skip data alignment factor - skipLeb128(D); + if (!skipLeb128(D)) + return false; // Skip the return address register. In CIE version 1 this is a single // byte. In CIE version 3 this is an unsigned LEB128. - if (Version == 1) - readByte(D); - else - skipLeb128(D); + uint8_t Discard; + if (Version == 1) { + if (!readByte(D, Discard)) + return false; + } else { + if (!skipLeb128(D)) + return false; + } while (!AugString.empty()) { - switch (readByte(AugString)) { + uint8_t B; + if (!readByte(AugString, B)) + return false; + switch (B) { case 'z': - skipLeb128(D); + if (!skipLeb128(D)) + return false; break; case 'R': - return readByte(D); + return readByte(D, Result); case 'P': { - uint8_t Enc = readByte(D); - if ((Enc & 0xf0) == dwarf::DW_EH_PE_aligned) - fatal("DW_EH_PE_aligned encoding for address of a personality routine " + uint8_t Enc; + if (!readByte(D, Enc)) + return false; + if ((Enc & 0xf0) == dwarf::DW_EH_PE_aligned) { + error("DW_EH_PE_aligned encoding for address of a personality routine " "handler not supported"); - unsigned EncSize = getSizeForEncoding(Enc); - Check(D.size() >= EncSize); + return false; + } + unsigned EncSize; + if (!getSizeForEncoding(Enc, EncSize)) + return false; + if (D.size() < EncSize) { + error("invalid encoding size"); + return false; + } D = D.slice(EncSize); break; } @@ -1093,10 +1145,12 @@ // handler break; default: - fatal("unknown .eh_frame augmentation string value"); + error("unknown .eh_frame augmentation string value"); + return false; } } - return dwarf::DW_EH_PE_absptr; + Result = dwarf::DW_EH_PE_absptr; + return false; } template @@ -1124,7 +1178,9 @@ unsigned Index = S->Offsets.size(); S->Offsets.push_back(std::make_pair(Offset, -1)); - uintX_t Length = readEntryLength(D); + uintX_t Length; + if (!readEntryLength(D, Length)) + return; // If CIE/FDE data length is zero then Length is 4, this // shall be considered a terminator and processing shall end. if (Length == 4) @@ -1141,7 +1197,8 @@ // CIE Cie C(S, Index); if (Config->EhFrameHdr) - C.FdeEncoding = getFdeEncoding(D); + if (!getFdeEncoding(D, C.FdeEncoding)) + return; StringRef Personality; if (HasReloc) { @@ -1158,14 +1215,18 @@ } OffsetToIndex[Offset] = P.first->second; } else { - if (!HasReloc) - fatal("FDE doesn't reference another section"); + if (!HasReloc) { + error("FDE doesn't reference another section"); + return; + } InputSectionBase *Target = S->getRelocTarget(*RelI); if (Target != &InputSection::Discarded && Target->isLive()) { uint32_t CieOffset = Offset + 4 - ID; auto I = OffsetToIndex.find(CieOffset); - if (I == OffsetToIndex.end()) - fatal("Invalid CIE reference"); + if (I == OffsetToIndex.end()) { + error("Invalid CIE reference"); + return; + } Cies[I->second].Fdes.push_back(EHRegion(S, Index)); Out::EhFrameHdr->reserveFde(); this->Header.sh_size += alignTo(Length, sizeof(uintX_t)); @@ -1178,29 +1239,35 @@ } template -typename EHOutputSection::uintX_t -EHOutputSection::readEntryLength(ArrayRef D) { +bool EHOutputSection::readEntryLength(ArrayRef D, + uintX_t &Result) { const endianness E = ELFT::TargetEndianness; - if (D.size() < 4) - fatal("Truncated CIE/FDE length"); + if (D.size() < 4) { + error("Truncated CIE/FDE length"); + return false; + } uint64_t Len = read32(D.data()); if (Len < UINT32_MAX) { - if (Len > (UINT32_MAX - 4)) - fatal("CIE/FIE size is too large"); - if (Len + 4 > D.size()) - fatal("CIE/FIE ends past the end of the section"); - return Len + 4; + if (Len > (UINT32_MAX - 4) || Len + 4 > D.size()) { + error("CIE/FIE size is invalid"); + return false; + } + Result = Len + 4; + return true; } - if (D.size() < 12) - fatal("Truncated CIE/FDE length"); + if (D.size() < 12) { + error("Truncated CIE/FDE length"); + return false; + } Len = read64(D.data() + 4); - if (Len > (UINT64_MAX - 12)) - fatal("CIE/FIE size is too large"); - if (Len + 12 > D.size()) - fatal("CIE/FIE ends past the end of the section"); - return Len + 12; + if (Len > (UINT64_MAX - 12) || Len + 12 > D.size()) { + error("CIE/FIE size is invalid"); + return false; + } + Result = Len + 12; + return true; } template @@ -1304,8 +1371,10 @@ uintX_t Offset = 0; while (!Data.empty()) { size_t End = findNull(Data, EntSize); - if (End == StringRef::npos) - fatal("String is not null terminated"); + if (End == StringRef::npos) { + error("String is not null terminated"); + return; + } StringRef Entry = Data.substr(0, End + EntSize); uintX_t OutputOffset = Builder.add(Entry); if (shouldTailMerge()) @@ -1460,7 +1529,8 @@ for (const std::unique_ptr> &File : Table.getObjectFiles()) { for (const Elf_Sym *Sym : File->KeptLocalSyms) { ErrorOr SymNameOrErr = Sym->getName(File->getStringTable()); - fatal(SymNameOrErr); + if (error(SymNameOrErr, "getName() failed")) + return; StringRef SymName = *SymNameOrErr; auto *ESym = reinterpret_cast(Buf); Index: test/ELF/invalid-cie-length2.s =================================================================== --- test/ELF/invalid-cie-length2.s +++ test/ELF/invalid-cie-length2.s @@ -6,4 +6,4 @@ .section .eh_frame .long 42 -// CHECK: CIE/FIE ends past the end of the section +// CHECK: CIE/FIE size is invalid Index: test/ELF/invalid-cie-length3.s =================================================================== --- test/ELF/invalid-cie-length3.s +++ test/ELF/invalid-cie-length3.s @@ -6,4 +6,4 @@ .section .eh_frame .long 0xFFFFFFFC -// CHECK: CIE/FIE size is too large +// CHECK: CIE/FIE size is invalid Index: test/ELF/invalid-cie-length5.s =================================================================== --- test/ELF/invalid-cie-length5.s +++ test/ELF/invalid-cie-length5.s @@ -7,4 +7,4 @@ .long 0xFFFFFFFF .quad 0xFFFFFFFFFFFFFFF4 -// CHECK: CIE/FIE size is too large +// CHECK: CIE/FIE size is invalid