Factor out the checking of string tables.
authorRafael Espindola <rafael.espindola@gmail.com>
Mon, 29 Jun 2015 14:39:25 +0000 (14:39 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Mon, 29 Jun 2015 14:39:25 +0000 (14:39 +0000)
This moves the error checking for string tables to getStringTable which returns
an ErrorOr<StringRef>.

This improves error checking, makes it uniform across all string tables and
makes it possible to check them once instead of once per name.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240950 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/ELF.h
include/llvm/Object/Error.h
lib/Object/Error.cpp
test/Object/Inputs/invalid-strtab-size.elf [new file with mode: 0644]
test/Object/invalid.test
tools/llvm-objdump/llvm-objdump.cpp
tools/llvm-readobj/ELFDumper.cpp
tools/obj2yaml/elf2yaml.cpp

index 662057a40b57e70fbd2b8439758639afef798db9..54ab3f922b833e5075ae220d9a06af4173885274 100644 (file)
@@ -172,8 +172,8 @@ private:
 
   const Elf_Ehdr *Header;
   const Elf_Shdr *SectionHeaderTable;
-  const Elf_Shdr *dot_shstrtab_sec; // Section header string table.
-  const Elf_Shdr *dot_strtab_sec;   // Symbol header string table.
+  StringRef DotShstrtab;            // Section header string table.
+  StringRef DotStrtab;              // Symbol header string table.
   const Elf_Shdr *dot_symtab_sec;   // Symbol table section.
 
   const Elf_Shdr *SymbolTableSectionHeaderIndex;
@@ -235,7 +235,7 @@ public:
   const T        *getEntry(uint32_t Section, uint32_t Entry) const;
   template <typename T>
   const T *getEntry(const Elf_Shdr *Section, uint32_t Entry) const;
-  ErrorOr<StringRef> getString(const Elf_Shdr *Section, uint32_t Offset) const;
+  ErrorOr<StringRef> getStringTable(const Elf_Shdr *Section) const;
   const char *getDynamicString(uintX_t Offset) const;
   ErrorOr<StringRef> getSymbolVersion(const Elf_Shdr *section,
                                       const Elf_Sym *Symb,
@@ -371,8 +371,7 @@ public:
   ///
   /// \p SymTab is used to lookup the string table to use to get the symbol's
   /// name.
-  ErrorOr<StringRef> getSymbolName(const Elf_Shdr *StrTab,
-                                   const Elf_Sym *Symb) const;
+  ErrorOr<StringRef> getSymbolName(StringRef StrTab, const Elf_Sym *Symb) const;
   ErrorOr<StringRef> getSectionName(const Elf_Shdr *Section) const;
   uint64_t getSymbolIndex(const Elf_Sym *sym) const;
   ErrorOr<ArrayRef<uint8_t> > getSectionContents(const Elf_Shdr *Sec) const;
@@ -545,15 +544,6 @@ ELFFile<ELFT>::getRelocationSymbol(const Elf_Shdr *Sec, const RelT *Rel) const {
       SymTable, getEntry<Elf_Sym>(SymTable, Rel->getSymbol(isMips64EL())));
 }
 
-// Verify that the last byte in the string table in a null.
-template <class ELFT>
-void ELFFile<ELFT>::VerifyStrTab(const Elf_Shdr *sh) const {
-  const char *strtab = (const char *)base() + sh->sh_offset;
-  if (strtab[sh->sh_size - 1] != 0)
-    // FIXME: Proper error handling.
-    report_fatal_error("String table must end with a null terminator!");
-}
-
 template <class ELFT>
 uint64_t ELFFile<ELFT>::getNumSections() const {
   assert(Header && "Header not initialized!");
@@ -577,8 +567,7 @@ typename ELFFile<ELFT>::uintX_t ELFFile<ELFT>::getStringTableIndex() const {
 
 template <class ELFT>
 ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC)
-    : Buf(Object), SectionHeaderTable(nullptr), dot_shstrtab_sec(nullptr),
-      dot_strtab_sec(nullptr), dot_symtab_sec(nullptr),
+    : Buf(Object), SectionHeaderTable(nullptr), dot_symtab_sec(nullptr),
       SymbolTableSectionHeaderIndex(nullptr), dot_gnu_version_sec(nullptr),
       dot_gnu_version_r_sec(nullptr), dot_gnu_version_d_sec(nullptr),
       dt_soname(nullptr) {
@@ -626,15 +615,18 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC)
       }
       SymbolTableSectionHeaderIndex = &Sec;
       break;
-    case ELF::SHT_SYMTAB:
+    case ELF::SHT_SYMTAB: {
       if (dot_symtab_sec) {
         // More than one .symtab!
         EC = object_error::parse_failed;
         return;
       }
       dot_symtab_sec = &Sec;
-      dot_strtab_sec = getSection(Sec.sh_link);
-      break;
+      ErrorOr<StringRef> SymtabOrErr = getStringTable(getSection(Sec.sh_link));
+      if ((EC = SymtabOrErr.getError()))
+        return;
+      DotStrtab = *SymtabOrErr;
+    } break;
     case ELF::SHT_DYNSYM: {
       if (DynSymRegion.Addr) {
         // More than one .dynsym!
@@ -688,11 +680,11 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC)
   }
 
   // Get string table sections.
-  dot_shstrtab_sec = getSection(getStringTableIndex());
-  if (dot_shstrtab_sec) {
-    // Verify that the last byte in the string table in a null.
-    VerifyStrTab(dot_shstrtab_sec);
-  }
+  ErrorOr<StringRef> SymtabOrErr =
+      getStringTable(getSection(getStringTableIndex()));
+  if ((EC = SymtabOrErr.getError()))
+    return;
+  DotShstrtab = *SymtabOrErr;
 
   // Build symbol name side-mapping if there is one.
   if (SymbolTableSectionHeaderIndex) {
@@ -865,13 +857,18 @@ ELFFile<ELFT>::getSection(uint32_t index) const {
 }
 
 template <class ELFT>
-ErrorOr<StringRef> ELFFile<ELFT>::getString(const Elf_Shdr *Section,
-                                            ELF::Elf32_Word Offset) const {
+ErrorOr<StringRef>
+ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const {
   if (Section->sh_type != ELF::SHT_STRTAB)
     return object_error::parse_failed;
-  if (Offset >= Section->sh_size)
+  uint64_t Offset = Section->sh_offset;
+  uint64_t Size = Section->sh_size;
+  if (Offset + Size > Buf.size())
     return object_error::parse_failed;
-  return StringRef((const char *)base() + Section->sh_offset + Offset);
+  StringRef Data((const char *)base() + Section->sh_offset, Size);
+  if (Data[Size - 1] != '\0')
+    return object_error::string_table_non_null_end;
+  return Data;
 }
 
 template <class ELFT>
@@ -884,7 +881,7 @@ const char *ELFFile<ELFT>::getDynamicString(uintX_t Offset) const {
 template <class ELFT>
 ErrorOr<StringRef>
 ELFFile<ELFT>::getStaticSymbolName(const Elf_Sym *Symb) const {
-  return getSymbolName(dot_strtab_sec, Symb);
+  return getSymbolName(DotStrtab, Symb);
 }
 
 template <class ELFT>
@@ -902,27 +899,40 @@ ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(const Elf_Sym *Symb,
 }
 
 template <class ELFT>
-ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(const Elf_Shdr *StrTab,
+ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(StringRef StrTab,
                                                 const Elf_Sym *Sym) const {
-  return getString(StrTab, Sym->st_name);
+  uint32_t Offset = Sym->st_name;
+  if (Offset >= StrTab.size())
+    return object_error::parse_failed;
+  return StringRef(StrTab.data() + Offset);
 }
 
 template <class ELFT>
 ErrorOr<StringRef>
 ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section) const {
-  return getString(dot_shstrtab_sec, Section->sh_name);
+  uint32_t Offset = Section->sh_name;
+  if (Offset >= DotShstrtab.size())
+    return object_error::parse_failed;
+  return StringRef(DotShstrtab.data() + Offset);
 }
 
 template <class ELFT>
 ErrorOr<StringRef> ELFFile<ELFT>::getSymbolVersion(const Elf_Shdr *section,
                                                    const Elf_Sym *symb,
                                                    bool &IsDefault) const {
+  StringRef StrTab;
+  if (section) {
+    ErrorOr<StringRef> StrTabOrErr = getStringTable(section);
+    if (std::error_code EC = StrTabOrErr.getError())
+      return EC;
+    StrTab = *StrTabOrErr;
+  }
   // Handle non-dynamic symbols.
   if (section != DynSymRegion.Addr && section != nullptr) {
     // Non-dynamic symbols can have versions in their names
     // A name of the form 'foo@V1' indicates version 'V1', non-default.
     // A name of the form 'foo@@V2' indicates version 'V2', default version.
-    ErrorOr<StringRef> SymName = getSymbolName(section, symb);
+    ErrorOr<StringRef> SymName = getSymbolName(StrTab, symb);
     if (!SymName)
       return SymName;
     StringRef Name = *SymName;
index c9db1b80b91697665ba8a96e6b63ffc584cdedbd..1b0b56787c5cd34342492903b6c7c28dddd2eb70 100644 (file)
@@ -27,6 +27,7 @@ enum class object_error {
   invalid_file_type,
   parse_failed,
   unexpected_eof,
+  string_table_non_null_end,
   bitcode_section_not_found,
   macho_small_load_command,
   macho_load_segment_too_many_sections,
index 644a178c16235539ba482c8f3d96540187212b67..5d613d77609f194570eeb67c1542821019c16c77 100644 (file)
@@ -41,6 +41,8 @@ std::string _object_error_category::message(int EV) const {
     return "Invalid data was encountered while parsing the file";
   case object_error::unexpected_eof:
     return "The end of the file was unexpectedly encountered";
+  case object_error::string_table_non_null_end:
+    return "String table must end with a null terminator";
   case object_error::bitcode_section_not_found:
     return "Bitcode section not found in object file";
   case object_error::macho_small_load_command:
diff --git a/test/Object/Inputs/invalid-strtab-size.elf b/test/Object/Inputs/invalid-strtab-size.elf
new file mode 100644 (file)
index 0000000..fb19746
Binary files /dev/null and b/test/Object/Inputs/invalid-strtab-size.elf differ
index 17cbb30c9c25490d8bb21657b309d63e2e995d99..73a6ad8021a4d85bc220a8e06473acd0cc1f0c79 100644 (file)
@@ -1,5 +1,6 @@
 RUN: not llvm-dwarfdump %p/Inputs/invalid-bad-rel-type.elf 2>&1 | FileCheck %s
 RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-type.elf 2>&1 | FileCheck %s
+RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-size.elf 2>&1 | FileCheck %s
 CHECK: Invalid data was encountered while parsing the file
 
 RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-non-null.elf 2>&1 | FileCheck --check-prefix=NON-NULL %s
index 610d54877eacd325c78811ab04945a6723e9b188..33308234e7d7e504b6b554bac7eee00474dd08f9 100644 (file)
@@ -324,7 +324,11 @@ static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
   const Elf_Shdr *SymTab = EF.getSection(sec->sh_link);
   assert(SymTab->sh_type == ELF::SHT_SYMTAB ||
          SymTab->sh_type == ELF::SHT_DYNSYM);
-  const Elf_Shdr *StrTab = EF.getSection(SymTab->sh_link);
+  const Elf_Shdr *StrTabSec = EF.getSection(SymTab->sh_link);
+  ErrorOr<StringRef> StrTabOrErr = EF.getStringTable(StrTabSec);
+  if (std::error_code EC = StrTabOrErr.getError())
+    return EC;
+  StringRef StrTab = *StrTabOrErr;
   uint8_t type;
   StringRef res;
   int64_t addend = 0;
index 76b71c517fdbc6d56f149c2ec1fbd4da47064497..b1ba0906f69691375e25e67a793ce4bb0b1936d4 100644 (file)
@@ -757,8 +757,11 @@ void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec,
       TargetName = SecName.get();
   } else if (Sym.first) {
     const Elf_Shdr *SymTable = Sym.first;
-    const Elf_Shdr *StrTable = Obj->getSection(SymTable->sh_link);
-    TargetName = errorOrDefault(Obj->getSymbolName(StrTable, Sym.second));
+    const Elf_Shdr *StrTableSec = Obj->getSection(SymTable->sh_link);
+    ErrorOr<StringRef> StrTableOrErr = Obj->getStringTable(StrTableSec);
+    if (!error(StrTableOrErr.getError()))
+      TargetName =
+          errorOrDefault(Obj->getSymbolName(*StrTableOrErr, Sym.second));
   }
 
   if (opts::ExpandRelocs) {
index db29d2db39088c96e2c6a362525453775fd318d8..73c83d897d99cbced44b3d8249fb0a00bdf487cc 100644 (file)
@@ -183,7 +183,11 @@ std::error_code ELFDumper<ELFT>::dumpRelocation(const Elf_Shdr *Shdr,
     return obj2yaml_error::success;
 
   const Elf_Shdr *SymTab = NamePair.first;
-  const Elf_Shdr *StrTab = Obj.getSection(SymTab->sh_link);
+  const Elf_Shdr *StrTabSec = Obj.getSection(SymTab->sh_link);
+  ErrorOr<StringRef> StrTabOrErr = Obj.getStringTable(StrTabSec);
+  if (std::error_code EC = StrTabOrErr.getError())
+    return EC;
+  StringRef StrTab = *StrTabOrErr;
 
   ErrorOr<StringRef> NameOrErr = Obj.getSymbolName(StrTab, NamePair.second);
   if (std::error_code EC = NameOrErr.getError())
@@ -302,7 +306,11 @@ ErrorOr<ELFYAML::Group *> ELFDumper<ELFT>::dumpGroup(const Elf_Shdr *Shdr) {
   // Get sh_info which is the signature.
   const Elf_Sym *symbol = Obj.getSymbol(Shdr->sh_info);
   const Elf_Shdr *symtab = Obj.getSection(Shdr->sh_link);
-  const Elf_Shdr *StrTab = Obj.getSection(symtab->sh_link);
+  const Elf_Shdr *StrTabSec = Obj.getSection(symtab->sh_link);
+  ErrorOr<StringRef> StrTabOrErr = Obj.getStringTable(StrTabSec);
+  if (std::error_code EC = StrTabOrErr.getError())
+    return EC;
+  StringRef StrTab = *StrTabOrErr;
   auto sectionContents = Obj.getSectionContents(Shdr);
   if (std::error_code ec = sectionContents.getError())
     return ec;