From ef6e5dc8332e80cecb5a1dda0a27b12f07955b0d Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Tue, 11 Dec 2018 00:09:06 +0000 Subject: [PATCH] llvm-objcopy: Improve/simplify llvm::Error handling during notes iteration Using an Error as an out parameter from an indirect operation like iteration as described in the documentation ( http://llvm.org/docs/ProgrammersManual.html#building-fallible-iterators-and-iterator-ranges ) seems to be a little fussy - so here's /one/ possible solution, though I'm not sure it's the right one. Alternatively such APIs may be better off being switched to a standard algorithm style, where they take a lambda to do the iteration work that is then called back into (eg: "Error e = obj.for_each_note([](const Note& N) { ... });"). This would be safer than having an unwritten assumption that the user of such an iteration cannot return early from the inside of the function - and must always exit through the gift shop... I mean error checking. (even though it's guaranteed that if you're mid-way through processing an iteration, it's not in an error state). Alternatively we'd need some other (the super untrustworthy/thing we've generally tried to avoid) error handling primitive that actually clears the error state entirely so it's safe to ignore. Fleshed this solution out a bit further during review - it now relies on op==/op!= comparison as the equivalent to "if (Err)" testing the Error. So just like an Error must be checked (even if it's in a success state), the Error hiding in the iterator must be checked after each increment (including by comparison with another iterator - perhaps this could be constrained to only checking if the iterator is compared to the end iterator? Not sure it's too important). So now even just creating the iterator and not incrementing it at all should still assert because the Error has not been checked. Reviewers: lhames, jakehehrlich Differential Revision: https://reviews.llvm.org/D55235 llvm-svn: 348811 --- include/llvm/Object/ELFTypes.h | 14 ++++++++++++-- tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 7 +------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index fafdcd7bdae..c1fadf8e210 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -642,14 +642,19 @@ class Elf_Note_Iterator_Impl // container, either cleanly or with an overflow error. void advanceNhdr(const uint8_t *NhdrPos, size_t NoteSize) { RemainingSize -= NoteSize; - if (RemainingSize == 0u) + if (RemainingSize == 0u) { + // Ensure that if the iterator walks to the end, the error is checked + // afterwards. + *Err = Error::success(); Nhdr = nullptr; - else if (sizeof(*Nhdr) > RemainingSize) + } else if (sizeof(*Nhdr) > RemainingSize) stopWithOverflowError(); else { Nhdr = reinterpret_cast *>(NhdrPos + NoteSize); if (Nhdr->getSize() > RemainingSize) stopWithOverflowError(); + else + *Err = Error::success(); } } @@ -657,6 +662,7 @@ class Elf_Note_Iterator_Impl explicit Elf_Note_Iterator_Impl(Error &Err) : Err(&Err) {} Elf_Note_Iterator_Impl(const uint8_t *Start, size_t Size, Error &Err) : RemainingSize(Size), Err(&Err) { + consumeError(std::move(Err)); assert(Start && "ELF note iterator starting at NULL"); advanceNhdr(Start, 0u); } @@ -670,6 +676,10 @@ public: return *this; } bool operator==(Elf_Note_Iterator_Impl Other) const { + if (!Nhdr) + (void)(bool)(*Other.Err); + if (!Other.Nhdr) + (void)(bool)(*Err); return Nhdr == Other.Nhdr; } bool operator!=(Elf_Note_Iterator_Impl Other) const { diff --git a/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/tools/llvm-objcopy/ELF/ELFObjcopy.cpp index 3b9f62e9b5f..8a136de24a8 100644 --- a/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -123,14 +123,9 @@ findBuildID(const object::ELFFile &In) { if (Phdr.p_type != PT_NOTE) continue; Error Err = Error::success(); - if (Err) - llvm_unreachable("Error::success() was an error."); - for (const auto &Note : In.notes(Phdr, Err)) { - if (Err) - return std::move(Err); + for (const auto &Note : In.notes(Phdr, Err)) if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU) return Note.getDesc(); - } if (Err) return std::move(Err); }