[llvm-bugs] [Bug 31091] New: libunwind: [ARM] EHABI getInfoFromEHABISection can fail if last .ARM.exidx table entry contains unwind information

via llvm-bugs llvm-bugs at lists.llvm.org
Mon Nov 21 06:16:59 PST 2016


https://llvm.org/bugs/show_bug.cgi?id=31091

            Bug ID: 31091
           Summary: libunwind: [ARM] EHABI getInfoFromEHABISection can
                    fail if last .ARM.exidx table entry contains unwind
                    information
           Product: libc++abi
           Version: 3.9
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: All Bugs
          Assignee: unassignedbugs at nondot.org
          Reporter: peter.smith at linaro.org
                CC: llvm-bugs at lists.llvm.org, mclow.lists at gmail.com
    Classification: Unclassified

If the last entry of the .ARM.exidx table contains unwinding information
libunwind will be unable to find it.

I have been testing out lld's ARM port against the libcxxabi tests and found a
few exceptions test failures. These failures would disappear if I reordered the
functions so that no function that threw and caught an exception was after
main.

I tracked the point of failure down to getInfoFromEHABISection: 

template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromEHABISection(
    pint_t pc,
    const UnwindInfoSections &sects) {
  EHABISectionIterator<A> begin =
      EHABISectionIterator<A>::begin(_addressSpace, sects);
  EHABISectionIterator<A> end =
      EHABISectionIterator<A>::end(_addressSpace, sects);

  EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc);
  if (itNextPC == begin || itNextPC == end)
    return false;
  EHABISectionIterator<A> itThisPC = itNextPC - 1;

  pint_t thisPC = itThisPC.functionAddress();
  pint_t nextPC = itNextPC.functionAddress();
  pint_t indexDataAddr = itThisPC.dataAddress();

If the last entry in the table contains the pc then upper_bound will return end
and return false. When I reorder the table entries main is last and the tests
don't throw through main so all thrown exceptions are caught as expected.

It turns out that ld.bfd inserts a sentinel EXIDX_CANTUNWIND .ARM.exidx entry
as the last entry in the table (usually the address of rodata is used) which
means that this implementation will always work when ld.bfd is used. 

A sentinel entry is useful as without it the scope of the last table entry is
the start of the program to the end of the address space (unless some other
information from the runtime is used to find the highest acceptable PC).
However I cannot find anywhere within the EHABI specification
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
that requires the presence of a sentinel entry. Unless I've missed something I
think that the libunwind implementation isn't compliant with the specification.

As ld.bfd always adds a terminating table entry this can't be reproduced with
it.

I used the lld ARM port using libcxx libcxxabi and libunwind running
catch_pointer_nullptr.pass.cpp (the templated tests are generated after main).

It may be possible, even beneficial to get lld to add a sentinel terminating
table entry in the same way, however I think it is still worth raising this as
there are other third party linkers that may use libunwind and won't
necessarily add a sentinel.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20161121/a9ee9290/attachment-0001.html>


More information about the llvm-bugs mailing list