<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <div class="moz-cite-prefix">On 30/08/2021 20:43, John McCall via
      cfe-dev wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:D3677A41-470C-43A8-A7E1-32E3501CA79D@apple.com">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <div style="font-family:sans-serif">
        <div style="white-space:normal">
          <p dir="auto">On 30 Aug 2021, at 2:59, Fāng-ruì Sòng wrote:</p>
        </div>
        <div style="white-space:normal">
          <blockquote style="border-left:2px solid #3983C4;
            color:#3983C4; margin:0 0 5px; padding-left:5px">
            <p dir="auto">On 2021-08-30, chuanqi.xcq wrote:</p>
            <blockquote style="border-left:2px solid #3983C4;
              color:#7CBF0C; margin:0 0 5px; padding-left:5px;
              border-left-color:#7CBF0C">
              <p dir="auto">Hi all,<br>
                <br>
                Let me introduce about the background:<br>
                I find that the compiler couldn't mark `foo` as
                `nounwind` in the following example:<br>
                <br>
                ```<br>
                void bar();<br>
                void foo() {<br>
                try {<br>
                bar();<br>
                } catch(...) {}<br>
                }<br>
                ```<br>
                <br>
                From my perspective, it is clear that foo wouldn't throw
                any exception. So it is natural to me that the compiler
                could mark foo as nounwind as an optimization. But it
                didn't.<br>
                This pattern occurs frequently in C++20 coroutine. So I
                tried to handle coroutine specially before in: <a
                  href="https://reviews.llvm.org/D108277"
                  moz-do-not-send="true" class="moz-txt-link-freetext">https://reviews.llvm.org/D108277</a>.<br>
                But the all the reviewers strongly suggested that we
                should handle this case generally for all of functions
                instead of coroutines only.<br>
                <br>
                Then when I looked into the details in IR, I found the
                reason is that __cxa_end_catch isn't nounwind.<br>
                Here is the IR generated:<br>
                <br>
                ```<br>
                ; Function Attrs: mustprogress uwtable<br>
                define dso_local void @_Z3foov() local_unnamed_addr #0
                personality i8* bitcast (i32 (...)*
                @__gxx_personality_v0 to i8*) {<br>
                invoke void @_Z3barv()<br>
                to label %5 unwind label %1<br>
                <br>
                1: ; preds = %0<br>
                %2 = landingpad { i8*, i32 }<br>
                catch i8* null<br>
                %3 = extractvalue { i8*, i32 } %2, 0<br>
                %4 = tail call i8* @__cxa_begin_catch(i8* %3) #2 ;
                nounwind<br>
                tail call void @__cxa_end_catch()<br>
                br label %5<br>
                <br>
                5: ; preds = %0, %1<br>
                ret void<br>
                }<br>
                ```<br>
                <br>
                I found that if I marked the call to __cxa_end_catch()
                as `nounwind`, the foo could be marked as `nounwind`. So
                I start to survey why __cxa_end_catch() isn't
                'nounwind'.<br>
                First is the comment on __cxa_end_catch() in libcxxabi:<br>
                <br>
                ```<br>
                Upon exit for any reason, a handler must call:<br>
                void __cxa_end_catch ();<br>
                <br>
                This routine can be called for either a native or
                foreign exception.<br>
                For a native exception:<br>
                * Locates the most recently caught exception and
                decrements its handler count.<br>
                * Removes the exception from the caught exception stack,
                if the handler count goes to zero.<br>
                * If the handler count goes down to zero, and the
                exception was not re-thrown<br>
                by throw, it locates the primary exception (which may be
                the same as the one<br>
                it's handling) and decrements its reference count. If
                that reference count<br>
                goes to zero, the function destroys the exception. In
                any case, if the current<br>
                exception is a dependent exception, it destroys that.<br>
                <br>
                For a foreign exception:<br>
                * If it has been rethrown, there is nothing to do.<br>
                * Otherwise delete the exception and pop the catch stack
                to empty.<br>
                ```<br>
                <br>
                I am not familiar with exception handling. But from the
                comment above, it looks like that __cxa_end_catch
                wouldn't throw.<br>
                Then in clang::ItaniumCXXABI, I found this:<br>
                <br>
                ```<br>
                A cleanup to call __cxa_end_catch. In many cases, the
                caught<br>
                exception type lets us state definitively that the
                thrown exception<br>
                type does not have a destructor. In particular:<br>
                - Catch-alls tell us nothing, so we have to
                conservatively<br>
                assume that the thrown exception might have a
                destructor.<br>
                - Catches by reference behave according to their base
                types.<br>
                - Catches of non-record types will only trigger for
                exceptions<br>
                of non-record types, which never have destructors.<br>
                - Catches of record types can trigger for arbitrary
                subclasses<br>
                of the caught type, so we have to assume the actual
                thrown<br>
                exception type might have a throwing destructor, even if
                the<br>
                caught type's destructor is trivial or nothrow.<br>
                ```<br>
                <br>
                It looks like that __cxa_end_catch would throw only if
                the exception caught has an destructor which may throw.</p>
            </blockquote>
            <p dir="auto">Yes...<br>
            </p>
            <blockquote style="border-left:2px solid #3983C4;
              color:#7CBF0C; margin:0 0 5px; padding-left:5px;
              border-left-color:#7CBF0C">
              <p dir="auto"> But I think the situation is rare. First as
                the comment says, an exception type doesn't have a
                destructor usually.<br>
                Then if it has a destructor, it is also rare that it may
                throw. Finally, it is a bad practice to throw from
                destructor which occurs in catch block.<br>
                So I want to provide an option to tell the compiler
                whether the exceptions in current project has a
                may-throw destructor. In this way, we could optimize the
                example in the beginning.</p>
            </blockquote>
            <p dir="auto">From GCC produced .gcc_except_table, it seems
              that GCC unconditionally<br>
              assumes that __cxa_begin_catch/__cxa_end_catch do not
              throw. GCC does<br>
              not emit call site records for the region with
              __cxa_end_catch.<br>
              <br>
              So I think we should unconditionally assume that
              __cxa_begin_catch/__cxa_end_catch don't throw as well.<br>
              Sent <a href="https://reviews.llvm.org/D108905"
                moz-do-not-send="true" class="moz-txt-link-freetext">https://reviews.llvm.org/D108905</a></p>
          </blockquote>
        </div>
        <div style="white-space:normal">
          <p dir="auto">That is not how this works. Here’s the path we
            need to take.</p>
          <p dir="auto">First, as I mentioned in the review, we need to
            figure out what the language standard expects to happen when
            the destructor for an exception throws at the end of a <code>catch</code>.
            Currently we are essentially treating this as undefined
            behavior, which I think is highly unlikely to be the intent
            of the standard.</p>
          <p dir="auto">If it’s allowed to unwind, then <code>__cxa_end_catch</code>
            can throw, and so the second step is to:<br>
            (1) fix the bugs in the language runtimes to handle this
            situation correctly and not leak the exception object, and
            then<br>
            (2) fix GCC to stop unconditionally assuming that <code>__cxa_end_catch</code>
            does not throw.<br>
            We could then add an opt-in flag to globally assume that
            exception destructors never throw as an optimization if
            that’s really important for getting good code.</p>
        </div>
      </div>
    </blockquote>
    <p>FWIW, although I cannot read the GCC exception table to check
      what that contains, when looking at what happens at runtime GCC
      appears to handle this correctly (except possibly for a memory
      leak, no comment on that). Here is a full example which returns 0
      when compiled with GCC, regardless of optimisation level:</p>
    <p>void bar();<br>
      void foo() {<br>
        try {<br>
          bar();<br>
        } catch (...) {}<br>
      }<br>
      <br>
      struct S {<br>
        ~S() noexcept(false) { throw 0; }<br>
      };<br>
      <br>
      void bar() {<br>
        throw S();<br>
      }<br>
      <br>
      int main() {<br>
        try {<br>
          foo();<br>
        } catch (int) {<br>
          return 0;<br>
        }<br>
        return 1;<br>
      }</p>
    <p>clang is in agreement with GCC, except that this appears to
      expose a problem in libc++(abi): with libstdc++, behaviour is as
      with GCC, with libc++ it results in</p>
    <p>libc++abi: terminating with unexpected exception of type int<br>
      Aborted (core dumped)</p>
    <p>If it is decided that this program is valid, I'll report the
      libc++(abi) problem to the bug tracker and possibly see if I can
      figure out what's going on.<br>
    </p>
    <p> Intel disagrees and causes</p>
    <p>terminate called after throwing an instance of 'int'<br>
      Aborted (core dumped)</p>
    <p>even when not optimising, even though it is using libstdc++.</p>
    <blockquote type="cite"
      cite="mid:D3677A41-470C-43A8-A7E1-32E3501CA79D@apple.com">
      <div style="font-family:sans-serif">
        <div style="white-space:normal">
          <p dir="auto">If it’s supposed to call <code>std::terminate</code>,
            then we need to come to an agreement with the language
            runtimes about whose responsibility it is to ensure that the
            exception is caught and <code>std::terminate</code> is
            called. That means opening an issue with the Itanium C++
            ABI. If we decide it’s the compiler’s responsibility to pass
            a noexcept function as the exception destructor, then we
            need to fix Clang to wrap the destructor in a noexcept
            function when it’s not noexcept. If we decide it’s the
            runtime’s responsibility, we need to fix the runtimes to
            catch this exception and call <code>std::terminate</code>.
            In either of those casess, <code>__cxa_end_catch</code> is
            known not to throw. We could also decide it’s the compiler’s
            responsibility to call <code>std::terminate</code> if <code>__cxa_end_catch</code>
            throws, and if so then we have to do that; however, I think
            that would be a bad outcome.</p>
          <p dir="auto">John.</p>
        </div>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <pre class="moz-quote-pre" wrap="">_______________________________________________
cfe-dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>
<a class="moz-txt-link-freetext" href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a>
</pre>
    </blockquote>
  </body>
</html>