diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 3fb8e537fad..ed0ca68653f 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -317,6 +317,61 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, Load = LoadOrErr.get(); } } + if (!SymtabLoadCmd) { + if (DysymtabLoadCmd) { + // Diagnostic("truncated or malformed object (contains LC_DYSYMTAB load " + // "command without a LC_SYMTAB load command)"); + EC = object_error::parse_failed; + return; + } + } else if (DysymtabLoadCmd) { + MachO::symtab_command Symtab = + getStruct(this, SymtabLoadCmd); + MachO::dysymtab_command Dysymtab = + getStruct(this, DysymtabLoadCmd); + if (Dysymtab.nlocalsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) { + // Diagnostic("truncated or malformed object (ilocalsym in LC_DYSYMTAB " + // "load command extends past the end of the symbol table)" + EC = object_error::parse_failed; + return; + } + uint64_t big_size = Dysymtab.ilocalsym; + big_size += Dysymtab.nlocalsym; + if (Dysymtab.nlocalsym != 0 && big_size > Symtab.nsyms) { + // Diagnostic("truncated or malformed object (ilocalsym plus nlocalsym " + // "in LC_DYSYMTAB load command extends past the end of the symbol table)" + EC = object_error::parse_failed; + return; + } + if (Dysymtab.nextdefsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) { + // Diagnostic("truncated or malformed object (nextdefsym in LC_DYSYMTAB " + // "load command extends past the end of the symbol table)" + EC = object_error::parse_failed; + return; + } + big_size = Dysymtab.iextdefsym; + big_size += Dysymtab.nextdefsym; + if (Dysymtab.nextdefsym != 0 && big_size > Symtab.nsyms) { + // Diagnostic("truncated or malformed object (iextdefsym plus nextdefsym " + // "in LC_DYSYMTAB load command extends past the end of the symbol table)" + EC = object_error::parse_failed; + return; + } + if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) { + // Diagnostic("truncated or malformed object (nundefsym in LC_DYSYMTAB " + // "load command extends past the end of the symbol table)" + EC = object_error::parse_failed; + return; + } + big_size = Dysymtab.iundefsym; + big_size += Dysymtab.nundefsym; + if (Dysymtab.nundefsym != 0 && big_size > Symtab.nsyms) { + // Diagnostic("truncated or malformed object (iundefsym plus nundefsym " + // "in LC_DYSYMTAB load command extends past the end of the symbol table)" + EC = object_error::parse_failed; + return; + } + } assert(LoadCommands.size() == LoadCommandCount); } @@ -941,15 +996,20 @@ MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const { } basic_symbol_iterator MachOObjectFile::symbol_begin_impl() const { + DataRefImpl DRI; + MachO::symtab_command Symtab = getSymtabLoadCommand(); + if (!SymtabLoadCmd || Symtab.nsyms == 0) + return basic_symbol_iterator(SymbolRef(DRI, this)); + return getSymbolByIndex(0); } basic_symbol_iterator MachOObjectFile::symbol_end_impl() const { DataRefImpl DRI; - if (!SymtabLoadCmd) + MachO::symtab_command Symtab = getSymtabLoadCommand(); + if (!SymtabLoadCmd || Symtab.nsyms == 0) return basic_symbol_iterator(SymbolRef(DRI, this)); - MachO::symtab_command Symtab = getSymtabLoadCommand(); unsigned SymbolTableEntrySize = is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); @@ -960,15 +1020,12 @@ basic_symbol_iterator MachOObjectFile::symbol_end_impl() const { } basic_symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const { - DataRefImpl DRI; - if (!SymtabLoadCmd) - return basic_symbol_iterator(SymbolRef(DRI, this)); - MachO::symtab_command Symtab = getSymtabLoadCommand(); - if (Index >= Symtab.nsyms) + if (!SymtabLoadCmd || Index >= Symtab.nsyms) report_fatal_error("Requested symbol index is out of range."); unsigned SymbolTableEntrySize = is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); + DataRefImpl DRI; DRI.p = reinterpret_cast(getPtr(this, Symtab.symoff)); DRI.p += Index * SymbolTableEntrySize; return basic_symbol_iterator(SymbolRef(DRI, this)); diff --git a/test/Object/Inputs/macho-valid-0-nsyms b/test/Object/Inputs/macho-valid-0-nsyms new file mode 100644 index 00000000000..1a170ff8161 Binary files /dev/null and b/test/Object/Inputs/macho-valid-0-nsyms differ diff --git a/test/Object/macho-invalid.test b/test/Object/macho-invalid.test index 0cf264f8771..781c9367c1e 100644 --- a/test/Object/macho-invalid.test +++ b/test/Object/macho-invalid.test @@ -25,7 +25,11 @@ TOO-MANY-SECTS: Mach-O segment load command contains too many sections RUN: not llvm-objdump -t %p/Inputs/macho-invalid-bad-symbol-index 2>&1 \ RUN: | FileCheck -check-prefix BAD-SYMBOL %s -BAD-SYMBOL: Requested symbol index is out of range +BAD-SYMBOL: Invalid data was encountered while parsing the file. +RUN: llvm-objdump -t %p/Inputs/macho-valid-0-nsyms 2>&1 \ +RUN: | FileCheck -check-prefix ZERO-NSYMS %s +ZERO-NSYMS: SYMBOL TABLE +ZERO-NSYMS-NOT: Requested symbol index is out of range RUN: not llvm-objdump -t %p/Inputs/macho-invalid-symbol-name-past-eof 2>&1 \ RUN: | FileCheck -check-prefix NAME-PAST-EOF %s