diff options
-rw-r--r-- | include/llvm/Object/Archive.h | 14 | ||||
-rw-r--r-- | lib/Object/Archive.cpp | 315 | ||||
-rw-r--r-- | lib/Object/ArchiveWriter.cpp | 4 | ||||
-rw-r--r-- | test/tools/llvm-objdump/Inputs/libbogus10.a | 13 | ||||
-rw-r--r-- | test/tools/llvm-objdump/Inputs/libbogus6.a | bin | 0 -> 260 bytes | |||
-rw-r--r-- | test/tools/llvm-objdump/Inputs/libbogus7.a | 10 | ||||
-rw-r--r-- | test/tools/llvm-objdump/Inputs/libbogus8.a | 13 | ||||
-rw-r--r-- | test/tools/llvm-objdump/Inputs/libbogus9.a | 13 | ||||
-rw-r--r-- | test/tools/llvm-objdump/malformed-archives.test | 32 | ||||
-rw-r--r-- | tools/dsymutil/BinaryHolder.cpp | 4 | ||||
-rw-r--r-- | tools/llvm-ar/llvm-ar.cpp | 8 | ||||
-rw-r--r-- | tools/llvm-nm/llvm-nm.cpp | 13 | ||||
-rw-r--r-- | tools/llvm-objdump/MachODump.cpp | 15 | ||||
-rw-r--r-- | tools/llvm-objdump/llvm-objdump.cpp | 7 | ||||
-rw-r--r-- | tools/llvm-size/llvm-size.cpp | 7 |
15 files changed, 351 insertions, 117 deletions
diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 4a2c8178ddf..48691458482 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -36,7 +36,10 @@ public: // ArchiveMemberHeader() = default; /// Get the name without looking up long names. - llvm::StringRef getName() const; + Expected<llvm::StringRef> getRawName() const; + + /// Get the name looking up long names. + Expected<llvm::StringRef> getName(uint64_t Size) const; /// Members are not larger than 4GB. Expected<uint32_t> getSize() const; @@ -82,7 +85,7 @@ public: /// \brief Offset from Data to the start of the file. uint16_t StartOfFile; - bool isThinMember() const; + Expected<bool> isThinMember() const; public: Child(const Archive *Parent, const char *Start, Error *Err); @@ -96,9 +99,9 @@ public: const Archive *getParent() const { return Parent; } Expected<Child> getNext() const; - ErrorOr<StringRef> getName() const; + Expected<StringRef> getName() const; ErrorOr<std::string> getFullName() const; - StringRef getRawName() const { return Header.getName(); } + Expected<StringRef> getRawName() const { return Header.getRawName(); } sys::TimeValue getLastModified() const { return Header.getLastModified(); } @@ -118,7 +121,7 @@ public: ErrorOr<StringRef> getBuffer() const; uint64_t getChildOffset() const; - ErrorOr<MemoryBufferRef> getMemoryBufferRef() const; + Expected<MemoryBufferRef> getMemoryBufferRef() const; Expected<std::unique_ptr<Binary>> getAsBinary(LLVMContext *Context = nullptr) const; @@ -238,6 +241,7 @@ public: bool hasSymbolTable() const; StringRef getSymbolTable() const { return SymbolTable; } + StringRef getStringTable() const { return StringTable; } uint32_t getNumberOfSymbols() const; std::vector<std::unique_ptr<MemoryBuffer>> takeThinBuffers() { diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 8b225f00c62..c866c407d48 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -43,17 +43,17 @@ ArchiveMemberHeader::ArchiveMemberHeader(const Archive *Parent, return; ErrorAsOutParameter ErrAsOutParam(Err); - // TODO: For errors messages with the ArchiveMemberHeader class use the - // archive member name instead of the the offset to the archive member header. - // When there is also error getting the member name then use the offset to - // the member in the message. - if (Size < sizeof(ArMemHdrType)) { if (Err) { - uint64_t Offset = RawHeaderPtr - Parent->getData().data(); - *Err = malformedError("remaining size of archive too small for next " - "archive member header at offset " + - Twine(Offset)); + Twine Msg("remaining size of archive too small for next archive member " + "header "); + Expected<StringRef> NameOrErr = getName(Size); + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); + uint64_t Offset = RawHeaderPtr - Parent->getData().data(); + *Err = malformedError(Msg + "at offset " + Twine(Offset)); + } else + *Err = malformedError(Msg + "for " + Twine(NameOrErr.get())); } return; } @@ -64,18 +64,35 @@ ArchiveMemberHeader::ArchiveMemberHeader(const Archive *Parent, OS.write_escaped(llvm::StringRef(ArMemHdr->Terminator, sizeof(ArMemHdr->Terminator))); OS.flush(); - uint64_t Offset = RawHeaderPtr - Parent->getData().data(); - *Err = malformedError("terminator characters in archive member \"" + Buf + - "\" not the correct \"`\\n\" values for the " - "archive member header at offset " + Twine(Offset)); + Twine Msg("terminator characters in archive member \"" + Buf + "\" not " + "the correct \"`\\n\" values for the archive member header "); + Expected<StringRef> NameOrErr = getName(Size); + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); + uint64_t Offset = RawHeaderPtr - Parent->getData().data(); + *Err = malformedError(Msg + "at offset " + Twine(Offset)); + } else + *Err = malformedError(Msg + "for " + Twine(NameOrErr.get())); } return; } } -StringRef ArchiveMemberHeader::getName() const { +// This gets the raw name from the ArMemHdr->Name field and checks that it is +// valid for the kind of archive. If it is not valid it returns an Error. +Expected<StringRef> ArchiveMemberHeader::getRawName() const { char EndCond; - if (ArMemHdr->Name[0] == '/' || ArMemHdr->Name[0] == '#') + auto Kind = Parent->kind(); + if (Kind == Archive::K_BSD || Kind == Archive::K_DARWIN64) { + if (ArMemHdr->Name[0] == ' ') { + uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) - + Parent->getData().data(); + return malformedError("name contains a leading space for archive member " + "header at offset " + Twine(Offset)); + } + EndCond = ' '; + } + else if (ArMemHdr->Name[0] == '/' || ArMemHdr->Name[0] == '#') EndCond = ' '; else EndCond = '/'; @@ -88,6 +105,105 @@ StringRef ArchiveMemberHeader::getName() const { return llvm::StringRef(ArMemHdr->Name, end); } +// This gets the name looking up long names. Size is the size of the archive +// member including the header, so the size of any name following the header +// is checked to make sure it does not overflow. +Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const { + + // This can be called from the ArchiveMemberHeader constructor when the + // archive header is truncated to produce an error message with the name. + // Make sure the name field is not truncated. + if (Size < offsetof(ArMemHdrType, Name) + sizeof(ArMemHdr->Name)) { + uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) - + Parent->getData().data(); + return malformedError("archive header truncated before the name field " + "for archive member header at offset " + + Twine(ArchiveOffset)); + } + + // The raw name itself can be invalid. + Expected<StringRef> NameOrErr = getRawName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef Name = NameOrErr.get(); + + // Check if it's a special name. + if (Name[0] == '/') { + if (Name.size() == 1) // Linker member. + return Name; + if (Name.size() == 2 && Name[1] == '/') // String table. + return Name; + // It's a long name. + // Get the string table offset. + std::size_t StringOffset; + if (Name.substr(1).rtrim(' ').getAsInteger(10, StringOffset)) { + std::string Buf; + raw_string_ostream OS(Buf); + OS.write_escaped(Name.substr(1).rtrim(' '), + sizeof(Name.substr(1)).rtrim(' ')); + OS.flush(); + uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) - + Parent->getData().data(); + return malformedError("long name offset characters after the '/' are " + "not all decimal numbers: '" + Buf + "' for " + "archive member header at offset " + + Twine(ArchiveOffset)); + } + + // Verify it. + if (StringOffset >= Parent->getStringTable().size()) { + uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) - + Parent->getData().data(); + return malformedError("long name offset " + Twine(StringOffset) + " past " + "the end of the string table for archive member " + "header at offset " + Twine(ArchiveOffset)); + } + const char *addr = Parent->getStringTable().begin() + StringOffset; + + // GNU long file names end with a "/\n". + if (Parent->kind() == Archive::K_GNU || + Parent->kind() == Archive::K_MIPS64) { + StringRef::size_type End = StringRef(addr).find('\n'); + return StringRef(addr, End - 1); + } + return StringRef(addr); + } else if (Name.startswith("#1/")) { + uint64_t NameLength; + if (Name.substr(3).rtrim(' ').getAsInteger(10, NameLength)) { + std::string Buf; + raw_string_ostream OS(Buf); + OS.write_escaped(Name.substr(3).rtrim(' '), + sizeof(Name.substr(3)).rtrim(' ')); + OS.flush(); + uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) - + Parent->getData().data(); + return malformedError("long name length characters after the #1/ are " + "not all decimal numbers: '" + Buf + "' for " + "archive member header at offset " + + Twine(ArchiveOffset)); + } + if (getSizeOf() + NameLength > Size) { + uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) - + Parent->getData().data(); + return malformedError("long name length: " + Twine(NameLength) + + " extends past the end of the member or archive " + "for archive member header at offset " + + Twine(ArchiveOffset)); + } + return StringRef(reinterpret_cast<const char *>(ArMemHdr) + getSizeOf(), + NameLength).rtrim('\0'); + } else { + // It is not a long name so trim the blanks at the end of the name. + if (Name[Name.size() - 1] != '/') { + return Name.rtrim(' '); + } + } + // It's a simple name. + if (Name[Name.size() - 1] == '/') + return Name.substr(0, Name.size() - 1); + return Name; +} + Expected<uint32_t> ArchiveMemberHeader::getSize() const { uint32_t Ret; if (llvm::StringRef(ArMemHdr->Size, @@ -166,7 +282,14 @@ Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err) uint64_t Size = Header.getSizeOf(); Data = StringRef(Start, Size); - if (!isThinMember()) { + Expected<bool> isThinOrErr = isThinMember(); + if (!isThinOrErr) { + if (Err) + *Err = isThinOrErr.takeError(); + return; + } + bool isThin = isThinOrErr.get(); + if (!isThin) { Expected<uint64_t> MemberSize = getRawSize(); if (!MemberSize) { if (Err) @@ -180,11 +303,30 @@ Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err) // Setup StartOfFile and PaddingBytes. StartOfFile = Header.getSizeOf(); // Don't include attached name. - StringRef Name = getRawName(); + Expected<StringRef> NameOrErr = getRawName(); + if (!NameOrErr){ + if (Err) + *Err = NameOrErr.takeError(); + return; + } + StringRef Name = NameOrErr.get(); if (Name.startswith("#1/")) { uint64_t NameSize; - if (Name.substr(3).rtrim(' ').getAsInteger(10, NameSize)) - llvm_unreachable("Long name length is not an integer"); + if (Name.substr(3).rtrim(' ').getAsInteger(10, NameSize)) { + if (Err) { + std::string Buf; + raw_string_ostream OS(Buf); + OS.write_escaped(Name.substr(3).rtrim(' '), + sizeof(Name.substr(3)).rtrim(' ')); + OS.flush(); + uint64_t Offset = Start - Parent->getData().data(); + *Err = malformedError("long name length characters after the #1/ are " + "not all decimal numbers: '" + Buf + "' for " + "archive member header at offset " + + Twine(Offset)); + return; + } + } StartOfFile += NameSize; } } @@ -203,16 +345,22 @@ Expected<uint64_t> Archive::Child::getRawSize() const { return Header.getSize(); } -bool Archive::Child::isThinMember() const { - StringRef Name = Header.getName(); +Expected<bool> Archive::Child::isThinMember() const { + Expected<StringRef> NameOrErr = Header.getRawName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef Name = NameOrErr.get(); return Parent->IsThin && Name != "/" && Name != "//"; } ErrorOr<std::string> Archive::Child::getFullName() const { - assert(isThinMember()); - ErrorOr<StringRef> NameOrErr = getName(); - if (std::error_code EC = NameOrErr.getError()) - return EC; + Expected<bool> isThin = isThinMember(); + if (!isThin) + return errorToErrorCode(isThin.takeError()); + assert(isThin.get()); + Expected<StringRef> NameOrErr = getName(); + if (!NameOrErr) + return errorToErrorCode(NameOrErr.takeError()); StringRef Name = *NameOrErr; if (sys::path::is_absolute(Name)) return Name; @@ -224,7 +372,11 @@ ErrorOr<std::string> Archive::Child::getFullName() const { } ErrorOr<StringRef> Archive::Child::getBuffer() const { - if (!isThinMember()) { + Expected<bool> isThinOrErr = isThinMember(); + if (!isThinOrErr) + return errorToErrorCode(isThinOrErr.takeError()); + bool isThin = isThinOrErr.get(); + if (!isThin) { Expected<uint32_t> Size = getSize(); if (!Size) return errorToErrorCode(Size.takeError()); @@ -257,8 +409,9 @@ Expected<Archive::Child> Archive::Child::getNext() const { if (NextLoc > Parent->Data.getBufferEnd()) { Twine Msg("offset to next archive member past the end of the archive after " "member "); - ErrorOr<StringRef> NameOrErr = getName(); - if (NameOrErr.getError()) { + Expected<StringRef> NameOrErr = getName(); + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); uint64_t Offset = Data.data() - Parent->getData().data(); return malformedError(Msg + "at offset " + Twine(Offset)); } else @@ -279,64 +432,34 @@ uint64_t Archive::Child::getChildOffset() const { return offset; } -ErrorOr<StringRef> Archive::Child::getName() const { - StringRef name = getRawName(); - // Check if it's a special name. - if (name[0] == '/') { - if (name.size() == 1) // Linker member. - return name; - if (name.size() == 2 && name[1] == '/') // String table. - return name; - // It's a long name. - // Get the offset. - std::size_t offset; - if (name.substr(1).rtrim(' ').getAsInteger(10, offset)) - llvm_unreachable("Long name offset is not an integer"); - - // Verify it. - if (offset >= Parent->StringTable.size()) - return object_error::parse_failed; - const char *addr = Parent->StringTable.begin() + offset; - - // GNU long file names end with a "/\n". - if (Parent->kind() == K_GNU || Parent->kind() == K_MIPS64) { - StringRef::size_type End = StringRef(addr).find('\n'); - return StringRef(addr, End - 1); - } - return StringRef(addr); - } else if (name.startswith("#1/")) { - uint64_t name_size; - if (name.substr(3).rtrim(' ').getAsInteger(10, name_size)) - llvm_unreachable("Long name length is not an ingeter"); - return Data.substr(Header.getSizeOf(), name_size).rtrim('\0'); - } else { - // It is not a long name so trim the blanks at the end of the name. - if (name[name.size() - 1] != '/') { - return name.rtrim(' '); - } - } - // It's a simple name. - if (name[name.size() - 1] == '/') - return name.substr(0, name.size() - 1); - return name; +Expected<StringRef> Archive::Child::getName() const { + Expected<uint64_t> RawSizeOrErr = getRawSize(); + if (!RawSizeOrErr) + return RawSizeOrErr.takeError(); + uint64_t RawSize = RawSizeOrErr.get(); + Expected<StringRef> NameOrErr = Header.getName(Header.getSizeOf() + RawSize); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef Name = NameOrErr.get(); + return Name; } -ErrorOr<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const { - ErrorOr<StringRef> NameOrErr = getName(); - if (std::error_code EC = NameOrErr.getError()) - return EC; +Expected<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const { + Expected<StringRef> NameOrErr = getName(); + if (!NameOrErr) + return NameOrErr.takeError(); StringRef Name = NameOrErr.get(); ErrorOr<StringRef> Buf = getBuffer(); if (std::error_code EC = Buf.getError()) - return EC; + return errorCodeToError(EC); return MemoryBufferRef(*Buf, Name); } Expected<std::unique_ptr<Binary>> Archive::Child::getAsBinary(LLVMContext *Context) const { - ErrorOr<MemoryBufferRef> BuffOrErr = getMemoryBufferRef(); - if (std::error_code EC = BuffOrErr.getError()) - return errorCodeToError(EC); + Expected<MemoryBufferRef> BuffOrErr = getMemoryBufferRef(); + if (!BuffOrErr) + return BuffOrErr.takeError(); auto BinaryOrErr = createBinary(BuffOrErr.get(), Context); if (BinaryOrErr) @@ -372,17 +495,20 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) return; } + // Make sure Format is initialized before any call to + // ArchiveMemberHeader::getName() is made. This could be a valid empty + // archive which is the same in all formats. So claiming it to be gnu to is + // fine if not totally correct before we look for a string table or table of + // contents. + Format = K_GNU; + // Get the special members. child_iterator I = child_begin(Err, false); if (Err) return; child_iterator E = child_end(); - // This is at least a valid empty archive. Since an empty archive is the - // same in all formats, just claim it to be gnu to make sure Format is - // initialized. - Format = K_GNU; - + // See if this is a valid empty archive and if so return. if (I == E) { Err = Error::success(); return; @@ -397,7 +523,12 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) return false; }; - StringRef Name = C->getRawName(); + Expected<StringRef> NameOrErr = C->getRawName(); + if (!NameOrErr) { + Err = NameOrErr.takeError(); + return; + } + StringRef Name = NameOrErr.get(); // Below is the pattern that is used to figure out the archive format // GNU archive format @@ -437,9 +568,9 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) if (Name.startswith("#1/")) { Format = K_BSD; // We know this is BSD, so getName will work since there is no string table. - ErrorOr<StringRef> NameOrErr = C->getName(); - if (auto ec = NameOrErr.getError()) { - Err = errorCodeToError(ec); + Expected<StringRef> NameOrErr = C->getName(); + if (!NameOrErr) { + Err = NameOrErr.takeError(); return; } Name = NameOrErr.get(); @@ -481,7 +612,12 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) Err = Error::success(); return; } - Name = C->getRawName(); + Expected<StringRef> NameOrErr = C->getRawName(); + if (!NameOrErr) { + Err = NameOrErr.takeError(); + return; + } + Name = NameOrErr.get(); } if (Name == "//") { @@ -522,7 +658,12 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) return; } - Name = C->getRawName(); + NameOrErr = C->getRawName(); + if (!NameOrErr) { + Err = NameOrErr.takeError(); + return; + } + Name = NameOrErr.get(); if (Name == "//") { // The string table is never an external member, so we just assert on the diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp index 53573262104..922d1b78667 100644 --- a/lib/Object/ArchiveWriter.cpp +++ b/lib/Object/ArchiveWriter.cpp @@ -40,9 +40,9 @@ NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) Expected<NewArchiveMember> NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, bool Deterministic) { - ErrorOr<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef(); + Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef(); if (!BufOrErr) - return errorCodeToError(BufOrErr.getError()); + return BufOrErr.takeError(); NewArchiveMember M; M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false); diff --git a/test/tools/llvm-objdump/Inputs/libbogus10.a b/test/tools/llvm-objdump/Inputs/libbogus10.a new file mode 100644 index 00000000000..9e1f7394c65 --- /dev/null +++ b/test/tools/llvm-objdump/Inputs/libbogus10.a @@ -0,0 +1,13 @@ +!<arch> +// 26 ` +1234567890123456hello.c/ + +/507 0 0 0 644 102 ` +#include <stdio.h> +#include <stdlib.h> +int +main() +{ + printf("Hello World\n"); + return EXIT_SUCCESS; +} diff --git a/test/tools/llvm-objdump/Inputs/libbogus6.a b/test/tools/llvm-objdump/Inputs/libbogus6.a Binary files differnew file mode 100644 index 00000000000..b15ee5b12c6 --- /dev/null +++ b/test/tools/llvm-objdump/Inputs/libbogus6.a diff --git a/test/tools/llvm-objdump/Inputs/libbogus7.a b/test/tools/llvm-objdump/Inputs/libbogus7.a new file mode 100644 index 00000000000..023f5437787 --- /dev/null +++ b/test/tools/llvm-objdump/Inputs/libbogus7.a @@ -0,0 +1,10 @@ +!<arch> +#1/@123$ 1469564779 124 0 100644 102 ` +#include <stdio.h> +#include <stdlib.h> +int +main() +{ + printf("Hello World\n"); + return EXIT_SUCCESS; +} diff --git a/test/tools/llvm-objdump/Inputs/libbogus8.a b/test/tools/llvm-objdump/Inputs/libbogus8.a new file mode 100644 index 00000000000..070c770846b --- /dev/null +++ b/test/tools/llvm-objdump/Inputs/libbogus8.a @@ -0,0 +1,13 @@ +!<arch> +foo.c 1444941645 124 0 100644 17 ` +void foo(void){} + +#1/1234 1469564779 124 0 100644 126 ` +1234567890123456Xhello.c#include <stdio.h> +#include <stdlib.h> +int +main() +{ + printf("Hello World\n"); + return EXIT_SUCCESS; +} diff --git a/test/tools/llvm-objdump/Inputs/libbogus9.a b/test/tools/llvm-objdump/Inputs/libbogus9.a new file mode 100644 index 00000000000..42a529b02b3 --- /dev/null +++ b/test/tools/llvm-objdump/Inputs/libbogus9.a @@ -0,0 +1,13 @@ +!<arch> +// 26 ` +1234567890123456hello.c/ + +/&a25* 0 0 0 644 102 ` +#include <stdio.h> +#include <stdlib.h> +int +main() +{ + printf("Hello World\n"); + return EXIT_SUCCESS; +} diff --git a/test/tools/llvm-objdump/malformed-archives.test b/test/tools/llvm-objdump/malformed-archives.test index c52bc8003f8..a9733d5939d 100644 --- a/test/tools/llvm-objdump/malformed-archives.test +++ b/test/tools/llvm-objdump/malformed-archives.test @@ -23,10 +23,38 @@ # RUN: %p/Inputs/libbogus4.a \ # RUN: 2>&1 | FileCheck -check-prefix=bogus4 %s -# bogus4: libbogus4.a': truncated or malformed archive (remaining size of archive too small for next archive member header at offset 170) +# bogus4: libbogus4.a': truncated or malformed archive (remaining size of archive too small for next archive member header for foo.c) # RUN: not llvm-objdump -macho -archive-headers \ # RUN: %p/Inputs/libbogus5.a \ # RUN: 2>&1 | FileCheck -check-prefix=bogus5 %s -# bogus5: libbogus5.a': truncated or malformed archive (terminator characters in archive member "@\n" not the correct "`\n" values for the archive member header at offset 8) +# bogus5: libbogus5.a': truncated or malformed archive (terminator characters in archive member "@\n" not the correct "`\n" values for the archive member header for hello.c) + +# RUN: not llvm-objdump -macho -archive-headers \ +# RUN: %p/Inputs/libbogus6.a \ +# RUN: 2>&1 | FileCheck -check-prefix=bogus6 %s + +# bogus6: libbogus6.a': truncated or malformed archive (name contains a leading space for archive member header at offset 96) + +# RUN: not llvm-objdump -macho -archive-headers \ +# RUN: %p/Inputs/libbogus7.a \ +# RUN: 2>&1 | FileCheck -check-prefix=bogus7 %s + +# bogus7: libbogus7.a': truncated or malformed archive (long name length characters after the #1/ are not all decimal numbers: '@123$' for archive member header at offset 8) + +# RUN: not llvm-objdump -macho -archive-headers \ +# RUN: %p/Inputs/libbogus8.a \ +# RUN: 2>&1 | FileCheck -check-prefix=bogus8 %s + +# bogus8: libbogus8.a(???) truncated or malformed archive (long name length: 1234 extends past the end of the member or archive for archive member header at offset 86) + +# RUN: not llvm-objdump -s %p/Inputs/libbogus9.a \ +# RUN: 2>&1 | FileCheck -check-prefix=bogus9 %s + +# bogus9: libbogus9.a(???) truncated or malformed archive (long name offset characters after the '/' are not all decimal numbers: '&a25*' for archive member header at offset 94) + +# RUN: not llvm-objdump -s %p/Inputs/libbogus10.a \ +# RUN: 2>&1 | FileCheck -check-prefix=bogus10 %s + +# bogus10: libbogus10.a(???) truncated or malformed archive (long name offset 507 past the end of the string table for archive member header at offset 94) diff --git a/tools/dsymutil/BinaryHolder.cpp b/tools/dsymutil/BinaryHolder.cpp index e45f7fefe08..abb4ea083c4 100644 --- a/tools/dsymutil/BinaryHolder.cpp +++ b/tools/dsymutil/BinaryHolder.cpp @@ -115,8 +115,8 @@ BinaryHolder::GetArchiveMemberBuffers(StringRef Filename, if (Verbose) outs() << "\tfound member in current archive.\n"; auto ErrOrMem = Child.getMemoryBufferRef(); - if (auto Err = ErrOrMem.getError()) - return Err; + if (!ErrOrMem) + return errorToErrorCode(ErrOrMem.takeError()); Buffers.push_back(*ErrOrMem); } } diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index dc1755de7d6..f52f9c376c1 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -409,8 +409,8 @@ static void performReadOperation(ArchiveOperation Operation, { Error Err; for (auto &C : OldArchive->children(Err)) { - ErrorOr<StringRef> NameOrErr = C.getName(); - failIfError(NameOrErr.getError()); + Expected<StringRef> NameOrErr = C.getName(); + failIfError(NameOrErr.takeError()); StringRef Name = NameOrErr.get(); if (Filter) { @@ -537,8 +537,8 @@ computeNewArchiveMembers(ArchiveOperation Operation, Error Err; for (auto &Child : OldArchive->children(Err)) { int Pos = Ret.size(); - ErrorOr<StringRef> NameOrErr = Child.getName(); - failIfError(NameOrErr.getError()); + Expected<StringRef> NameOrErr = Child.getName(); + failIfError(NameOrErr.takeError()); StringRef Name = NameOrErr.get(); if (Name == PosName) { assert(AddAfter || AddBefore); diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 9b2f5220bad..424303b1695 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -198,13 +198,14 @@ static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, HadError = true; errs() << ToolName << ": " << FileName; - ErrorOr<StringRef> NameOrErr = C.getName(); + Expected<StringRef> NameOrErr = C.getName(); // TODO: if we have a error getting the name then it would be nice to print // the index of which archive member this is and or its offset in the // archive instead of "???" as the name. - if (NameOrErr.getError()) + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); errs() << "(" << "???" << ")"; - else + } else errs() << "(" << NameOrErr.get() << ")"; if (!ArchitectureName.empty()) @@ -1099,9 +1100,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { ErrorOr<Archive::Child> C = I->getMember(); if (error(C.getError())) return; - ErrorOr<StringRef> FileNameOrErr = C->getName(); - if (error(FileNameOrErr.getError())) + Expected<StringRef> FileNameOrErr = C->getName(); + if (!FileNameOrErr) { + error(FileNameOrErr.takeError(), Filename); return; + } StringRef SymName = I->getName(); outs() << SymName << " in " << FileNameOrErr.get() << "\n"; } diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 10cd407e377..8d924e568b7 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -1521,16 +1521,23 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C, } if (verbose) { - ErrorOr<StringRef> NameOrErr = C.getName(); - if (NameOrErr.getError()) { - StringRef RawName = C.getRawName(); + Expected<StringRef> NameOrErr = C.getName(); + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); + Expected<StringRef> NameOrErr = C.getRawName(); + if (!NameOrErr) + report_error(Filename, C, NameOrErr.takeError(), ArchitectureName); + StringRef RawName = NameOrErr.get(); outs() << RawName << "\n"; } else { StringRef Name = NameOrErr.get(); outs() << Name << "\n"; } } else { - StringRef RawName = C.getRawName(); + Expected<StringRef> NameOrErr = C.getRawName(); + if (!NameOrErr) + report_error(Filename, C, NameOrErr.takeError(), ArchitectureName); + StringRef RawName = NameOrErr.get(); outs() << RawName << "\n"; } } diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index ed55c918b58..7482965b784 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -312,13 +312,14 @@ LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName, const object::Archive::Child &C, llvm::Error E, StringRef ArchitectureName) { - ErrorOr<StringRef> NameOrErr = C.getName(); + Expected<StringRef> NameOrErr = C.getName(); // TODO: if we have a error getting the name then it would be nice to print // the index of which archive member this is and or its offset in the // archive instead of "???" as the name. - if (NameOrErr.getError()) + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); llvm::report_error(ArchiveName, "???", std::move(E), ArchitectureName); - else + } else llvm::report_error(ArchiveName, NameOrErr.get(), std::move(E), ArchitectureName); } diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index c5966ead4b6..4ecfcc2df10 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -114,13 +114,14 @@ static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, HadError = true; errs() << ToolName << ": " << FileName; - ErrorOr<StringRef> NameOrErr = C.getName(); + Expected<StringRef> NameOrErr = C.getName(); // TODO: if we have a error getting the name then it would be nice to print // the index of which archive member this is and or its offset in the // archive instead of "???" as the name. - if (NameOrErr.getError()) + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); errs() << "(" << "???" << ")"; - else + } else errs() << "(" << NameOrErr.get() << ")"; if (!ArchitectureName.empty()) |