llvm.org GIT mirror llvm / fa90761
Next step along the way to getting good error messages for bad archives. This step builds on Lang Hames work to change Archive::child_iterator for better interoperation with Error/Expected. Building on that it is now possible to return an error message when the size field of an archive contains non-decimal characters. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@276025 91177308-0d34-0410-b5e6-96231b3b80d8 Kevin Enderby 4 years ago
5 changed file(s) with 78 addition(s) and 59 deletion(s). Raw diff Collapse all Expand all
3737 llvm::StringRef getName() const;
3838
3939 /// Members are not larger than 4GB.
40 ErrorOr getSize() const;
40 Expected getSize() const;
4141
4242 sys::fs::perms getAccessMode() const;
4343 sys::TimeValue getLastModified() const;
6666 bool isThinMember() const;
6767
6868 public:
69 Child(const Archive *Parent, const char *Start, std::error_code *EC);
69 Child(const Archive *Parent, const char *Start, Error *Err);
7070 Child(const Archive *Parent, StringRef Data, uint16_t StartOfFile);
7171
7272 bool operator ==(const Child &other) const {
7575 }
7676
7777 const Archive *getParent() const { return Parent; }
78 ErrorOr getNext() const;
78 Expected getNext() const;
7979
8080 ErrorOr getName() const;
8181 ErrorOr getFullName() const;
9292 return getHeader()->getAccessMode();
9393 }
9494 /// \return the size of the archive member without the header or padding.
95 ErrorOr getSize() const;
95 Expected getSize() const;
9696 /// \return the size in the archive header for this member.
97 ErrorOr getRawSize() const;
97 Expected getRawSize() const;
9898
9999 ErrorOr getBuffer() const;
100100 uint64_t getChildOffset() const;
135135 else {
136136 ErrorAsOutParameter ErrAsOutParam(*E);
137137 C = C.getParent()->child_end().C;
138 *E = errorCodeToError(ChildOrErr.getError());
138 *E = ChildOrErr.takeError();
139139 E = nullptr;
140140 }
141141 return *this;
2525 static const char *const ThinMagic = "!\n";
2626
2727 void Archive::anchor() { }
28
29 static Error
30 malformedError(Twine Msg) {
31 std::string StringMsg = "truncated or malformed archive (" + Msg.str() + ")";
32 return make_error(std::move(StringMsg),
33 object_error::parse_failed);
34 }
2835
2936 StringRef ArchiveMemberHeader::getName() const {
3037 char EndCond;
4148 return llvm::StringRef(Name, end);
4249 }
4350
44 ErrorOr ArchiveMemberHeader::getSize() const {
51 Expected ArchiveMemberHeader::getSize() const {
4552 uint32_t Ret;
46 if (llvm::StringRef(Size, sizeof(Size)).rtrim(" ").getAsInteger(10, Ret))
47 return object_error::parse_failed; // Size is not a decimal number.
53 if (llvm::StringRef(Size, sizeof(Size)).rtrim(" ").getAsInteger(10, Ret)) {
54 std::string Buf;
55 raw_string_ostream OS(Buf);
56 OS.write_escaped(llvm::StringRef(Size, sizeof(Size)).rtrim(" "));
57 OS.flush();
58 return malformedError("characters in size field in archive header are not "
59 "all decimal numbers: '" + Buf + "'");
60 }
4861 return Ret;
4962 }
5063
90103 uint16_t StartOfFile)
91104 : Parent(Parent), Data(Data), StartOfFile(StartOfFile) {}
92105
93 Archive::Child::Child(const Archive *Parent, const char *Start,
94 std::error_code *EC)
106 Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err)
95107 : Parent(Parent) {
96108 if (!Start)
97109 return;
99111 uint64_t Size = sizeof(ArchiveMemberHeader);
100112 Data = StringRef(Start, Size);
101113 if (!isThinMember()) {
102 ErrorOr MemberSize = getRawSize();
103 if ((*EC = MemberSize.getError()))
114 Expected MemberSize = getRawSize();
115 if (!MemberSize) {
116 if (Err) {
117 ErrorAsOutParameter ErrAsOutParam(*Err);
118 *Err = MemberSize.takeError();
119 }
104120 return;
121 }
105122 Size += MemberSize.get();
106123 Data = StringRef(Start, Size);
107124 }
118135 }
119136 }
120137
121 ErrorOr Archive::Child::getSize() const {
138 Expected Archive::Child::getSize() const {
122139 if (Parent->IsThin) {
123 ErrorOr Size = getHeader()->getSize();
124 if (std::error_code EC = Size.getError())
125 return EC;
140 Expected Size = getHeader()->getSize();
141 if (!Size)
142 return Size.takeError();
126143 return Size.get();
127144 }
128145 return Data.size() - StartOfFile;
129146 }
130147
131 ErrorOr Archive::Child::getRawSize() const {
132 ErrorOr Size = getHeader()->getSize();
133 if (std::error_code EC = Size.getError())
134 return EC;
135 return Size.get();
148 Expected Archive::Child::getRawSize() const {
149 return getHeader()->getSize();
136150 }
137151
138152 bool Archive::Child::isThinMember() const {
157171
158172 ErrorOr Archive::Child::getBuffer() const {
159173 if (!isThinMember()) {
160 ErrorOr Size = getSize();
161 if (std::error_code EC = Size.getError())
162 return EC;
174 Expected Size = getSize();
175 if (!Size)
176 return errorToErrorCode(Size.takeError());
163177 return StringRef(Data.data() + StartOfFile, Size.get());
164178 }
165179 ErrorOr FullNameOrEr = getFullName();
173187 return Parent->ThinBuffers.back()->getBuffer();
174188 }
175189
176 ErrorOr Archive::Child::getNext() const {
190 Expected Archive::Child::getNext() const {
177191 size_t SpaceToSkip = Data.size();
178192 // If it's odd, add 1 to make it even.
179193 if (SpaceToSkip & 1)
187201
188202 // Check to see if this is past the end of the archive.
189203 if (NextLoc > Parent->Data.getBufferEnd())
190 return object_error::parse_failed;
191
192 std::error_code EC;
193 Child Ret(Parent, NextLoc, &EC);
194 if (EC)
195 return EC;
204 return malformedError("offset to next archive member past the end of the "
205 "archive");
206
207 Error Err;
208 Child Ret(Parent, NextLoc, &Err);
209 if (Err)
210 return std::move(Err);
196211 return Ret;
197212 }
198213
471486 &Err);
472487
473488 const char *Loc = Data.getBufferStart() + strlen(Magic);
474 std::error_code EC;
475 Child C(this, Loc, &EC);
476 if (EC) {
477 ErrorAsOutParameter ErrAsOutParam(Err);
478 Err = errorCodeToError(EC);
489 Child C(this, Loc, &Err);
490 if (Err)
479491 return child_end();
480 }
481492 return child_iterator(C, &Err);
482493 }
483494
542553 }
543554
544555 const char *Loc = Parent->getData().begin() + Offset;
545 std::error_code EC;
546 Child C(Parent, Loc, &EC);
547 if (EC)
548 return EC;
556 Error Err;
557 Child C(Parent, Loc, &Err);
558 if (Err)
559 return errorToErrorCode(std::move(Err));
549560 return C;
550561 }
551562
44 # RUN: %p/Inputs/libbogus1.a \
55 # RUN: 2>&1 | FileCheck -check-prefix=bogus1 %s
66
7 # bogus1: Invalid data was encountered while parsing the file
7 # bogus1: libbogus1.a': truncated or malformed archive (characters in size field in archive header are not all decimal numbers: '10%')
88
99 # RUN: not llvm-objdump -macho -archive-headers \
1010 # RUN: %p/Inputs/libbogus2.a \
1111 # RUN: 2>&1 | FileCheck -check-prefix=bogus2 %s
1212
13 # bogus2: LLVM ERROR: Invalid data was encountered while parsing the file
13 # bogus2: libbogus2.a': truncated or malformed archive (characters in size field in archive header are not all decimal numbers: '1%')
1414
1515 # RUN: not llvm-objdump -macho -archive-headers \
1616 # RUN: %p/Inputs/libbogus3.a \
1717 # RUN: 2>&1 | FileCheck -check-prefix=bogus3 %s
1818
19 # bogus3: LLVM ERROR: Invalid data was encountered while parsing the file
19 # bogus3: libbogus3.a': truncated or malformed archive (offset to next archive member past the end of the archive)
342342 printMode(Mode & 007);
343343 outs() << ' ' << C.getUID();
344344 outs() << '/' << C.getGID();
345 ErrorOr Size = C.getSize();
346 failIfError(Size.getError());
345 Expected Size = C.getSize();
346 failIfError(Size.takeError());
347347 outs() << ' ' << format("%6llu", Size.get());
348348 outs() << ' ' << C.getLastModified().str();
349349 outs() << ' ';
14711471 }
14721472 }
14731473
1474 static void printArchiveChild(const Archive::Child &C, bool verbose,
1475 bool print_offset) {
1474 static void printArchiveChild(StringRef Filename, const Archive::Child &C,
1475 bool verbose, bool print_offset,
1476 StringRef ArchitectureName = StringRef()) {
14761477 if (print_offset)
14771478 outs() << C.getChildOffset() << "\t";
14781479 sys::fs::perms Mode = C.getAccessMode();
14971498 outs() << format("%3d/", UID);
14981499 unsigned GID = C.getGID();
14991500 outs() << format("%-3d ", GID);
1500 ErrorOr Size = C.getRawSize();
1501 if (std::error_code EC = Size.getError())
1502 report_fatal_error(EC.message());
1501 Expected Size = C.getRawSize();
1502 if (!Size)
1503 report_error(Filename, C, Size.takeError(), ArchitectureName);
15031504 outs() << format("%5" PRId64, Size.get()) << " ";
15041505
15051506 StringRef RawLastModified = C.getRawLastModified();
15331534 }
15341535 }
15351536
1536 static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) {
1537 static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,
1538 bool print_offset,
1539 StringRef ArchitectureName = StringRef()) {
15371540 Error Err;
15381541 for (const auto &C : A->children(Err, false))
1539 printArchiveChild(C, verbose, print_offset);
1542 printArchiveChild(Filename, C, verbose, print_offset, ArchitectureName);
1543
15401544 if (Err)
1541 report_fatal_error(std::move(Err));
1545 report_error(Filename, std::move(Err));
15421546 }
15431547
15441548 // ParseInputMachO() parses the named Mach-O file in Filename and handles the
15681572 if (Archive *A = dyn_cast(&Bin)) {
15691573 outs() << "Archive : " << Filename << "\n";
15701574 if (ArchiveHeaders)
1571 printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets);
1575 printArchiveHeaders(Filename, A, !NonVerbose, ArchiveMemberOffsets);
1576
15721577 Error Err;
15731578 for (auto &C : A->children(Err)) {
15741579 Expected> ChildOrErr = C.getAsBinary();
16251630 outs() << " (architecture " << ArchitectureName << ")";
16261631 outs() << "\n";
16271632 if (ArchiveHeaders)
1628 printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
1633 printArchiveHeaders(Filename, A.get(), !NonVerbose,
1634 ArchiveMemberOffsets, ArchitectureName);
16291635 Error Err;
16301636 for (auto &C : A->children(Err)) {
16311637 Expected> ChildOrErr = C.getAsBinary();
16801686 std::unique_ptr &A = *AOrErr;
16811687 outs() << "Archive : " << Filename << "\n";
16821688 if (ArchiveHeaders)
1683 printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
1689 printArchiveHeaders(Filename, A.get(), !NonVerbose,
1690 ArchiveMemberOffsets);
16841691 Error Err;
16851692 for (auto &C : A->children(Err)) {
16861693 Expected> ChildOrErr = C.getAsBinary();
17311738 outs() << " (architecture " << ArchitectureName << ")";
17321739 outs() << "\n";
17331740 if (ArchiveHeaders)
1734 printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
1741 printArchiveHeaders(Filename, A.get(), !NonVerbose,
1742 ArchiveMemberOffsets, ArchitectureName);
17351743 Error Err;
17361744 for (auto &C : A->children(Err)) {
17371745 Expected> ChildOrErr = C.getAsBinary();