summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Object/Archive.h14
-rw-r--r--lib/Object/Archive.cpp315
-rw-r--r--lib/Object/ArchiveWriter.cpp4
-rw-r--r--test/tools/llvm-objdump/Inputs/libbogus10.a13
-rw-r--r--test/tools/llvm-objdump/Inputs/libbogus6.abin0 -> 260 bytes
-rw-r--r--test/tools/llvm-objdump/Inputs/libbogus7.a10
-rw-r--r--test/tools/llvm-objdump/Inputs/libbogus8.a13
-rw-r--r--test/tools/llvm-objdump/Inputs/libbogus9.a13
-rw-r--r--test/tools/llvm-objdump/malformed-archives.test32
-rw-r--r--tools/dsymutil/BinaryHolder.cpp4
-rw-r--r--tools/llvm-ar/llvm-ar.cpp8
-rw-r--r--tools/llvm-nm/llvm-nm.cpp13
-rw-r--r--tools/llvm-objdump/MachODump.cpp15
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp7
-rw-r--r--tools/llvm-size/llvm-size.cpp7
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
new file mode 100644
index 00000000000..b15ee5b12c6
--- /dev/null
+++ b/test/tools/llvm-objdump/Inputs/libbogus6.a
Binary files differ
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())