[libcxx-commits] [libcxxabi] 632acec - [libunwind][ARM] Handle end of stack during unwind

Daniel Kiss via libcxx-commits libcxx-commits at lists.llvm.org
Fri Nov 26 04:26:56 PST 2021


Author: Daniel Kiss
Date: 2021-11-26T13:26:49+01:00
New Revision: 632acec73776c4d6f7073d6de04ed6b8bfd36e6d

URL: https://github.com/llvm/llvm-project/commit/632acec73776c4d6f7073d6de04ed6b8bfd36e6d
DIFF: https://github.com/llvm/llvm-project/commit/632acec73776c4d6f7073d6de04ed6b8bfd36e6d.diff

LOG: [libunwind][ARM] Handle end of stack during unwind

When unwind step reaches the end of the stack that means the force unwind should notify the stop function.
This is not an error, it could mean just the thread is cleaned up completely.

Reviewed By: #libunwind, mstorsjo

Differential Revision: https://reviews.llvm.org/D109856

Added: 
    libcxxabi/test/forced_unwind3.pass.cpp

Modified: 
    libcxxabi/src/cxa_personality.cpp
    libunwind/src/Unwind-EHABI.cpp

Removed: 
    


################################################################################
diff  --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index ccad45979db2a..f6e135f137c09 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -1004,9 +1004,14 @@ extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*,
 static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,
                                            _Unwind_Context* context)
 {
-    if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK)
-        return _URC_FAILURE;
+  switch (__gnu_unwind_frame(unwind_exception, context)) {
+  case _URC_OK:
     return _URC_CONTINUE_UNWIND;
+  case _URC_END_OF_STACK:
+    return _URC_END_OF_STACK;
+  default:
+    return _URC_FAILURE;
+  }
 }
 
 // ARM register names

diff  --git a/libcxxabi/test/forced_unwind3.pass.cpp b/libcxxabi/test/forced_unwind3.pass.cpp
new file mode 100644
index 0000000000000..3bcc7978aeab8
--- /dev/null
+++ b/libcxxabi/test/forced_unwind3.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Let's run ForcedUnwind until it reaches end of the stack, this test simulates
+// what pthread_cancel does.
+
+// UNSUPPORTED: c++03
+// UNSUPPORTED: libcxxabi-no-threads
+// UNSUPPORTED: no-exceptions
+
+#include <assert.h>
+#include <exception>
+#include <stdlib.h>
+#include <string.h>
+#include <unwind.h>
+#include <thread>
+#include <tuple>
+#include <__cxxabi_config.h>
+
+// TODO: dump version back to 14 once clang is updated on the CI.
+#if defined(_LIBCXXABI_ARM_EHABI) && defined(__clang__) && __clang_major__ < 15
+// _Unwind_ForcedUnwind is not available or broken before version 14.
+int main(int, char**) { return 0; }
+
+#else
+static bool destructorCalled = false;
+
+struct myClass {
+  myClass() {}
+  ~myClass() {
+    assert(destructorCalled == false);
+    destructorCalled = true;
+  };
+};
+
+template <typename T>
+struct Stop;
+
+template <typename R, typename... Args>
+struct Stop<R (*)(Args...)> {
+  // The third argument of _Unwind_Stop_Fn is uint64_t in Itanium C++ ABI/LLVM
+  // libunwind while _Unwind_Exception_Class in libgcc.
+  typedef typename std::tuple_element<2, std::tuple<Args...>>::type type;
+
+  static _Unwind_Reason_Code stop(int, _Unwind_Action actions, type, struct _Unwind_Exception*, struct _Unwind_Context*,
+                                  void*) {
+    if (actions & _UA_END_OF_STACK) {
+      assert(destructorCalled == true);
+      exit(0);
+    }
+    return _URC_NO_REASON;
+  }
+};
+
+static void forced_unwind() {
+  _Unwind_Exception* exc = new _Unwind_Exception;
+  memset(&exc->exception_class, 0, sizeof(exc->exception_class));
+  exc->exception_cleanup = 0;
+  _Unwind_ForcedUnwind(exc, Stop<_Unwind_Stop_Fn>::stop, 0);
+  abort();
+}
+
+__attribute__((__noinline__)) static void test() {
+  myClass c{};
+  forced_unwind();
+  abort();
+}
+
+int main(int, char**) {
+  std::thread t{test};
+  t.join();
+  return -1;
+}
+#endif

diff  --git a/libunwind/src/Unwind-EHABI.cpp b/libunwind/src/Unwind-EHABI.cpp
index d3577c9f7cf8d..5959d2a25fead 100644
--- a/libunwind/src/Unwind-EHABI.cpp
+++ b/libunwind/src/Unwind-EHABI.cpp
@@ -187,9 +187,14 @@ static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state,
   if (result != _URC_CONTINUE_UNWIND)
     return result;
 
-  if (__unw_step(reinterpret_cast<unw_cursor_t *>(context)) != UNW_STEP_SUCCESS)
+  switch (__unw_step(reinterpret_cast<unw_cursor_t *>(context))) {
+  case UNW_STEP_SUCCESS:
+    return _URC_CONTINUE_UNWIND;
+  case UNW_STEP_END:
+    return _URC_END_OF_STACK;
+  default:
     return _URC_FAILURE;
-  return _URC_CONTINUE_UNWIND;
+  }
 }
 
 // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE /
@@ -678,12 +683,13 @@ static _Unwind_Reason_Code
 unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
                      _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop,
                      void *stop_parameter) {
+  bool endOfStack = false;
   // See comment at the start of unwind_phase1 regarding VRS integrity.
   __unw_init_local(cursor, uc);
   _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_force(ex_ojb=%p)",
                              static_cast<void *>(exception_object));
   // Walk each frame until we reach where search phase said to stop
-  while (true) {
+  while (!endOfStack) {
     // Update info about this frame.
     unw_proc_info_t frameInfo;
     if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
@@ -756,6 +762,14 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
         // We may get control back if landing pad calls _Unwind_Resume().
         __unw_resume(cursor);
         break;
+      case _URC_END_OF_STACK:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned "
+                                   "_URC_END_OF_STACK",
+                                   (void *)exception_object);
+        // Personalty routine did the step and it can't step forward.
+        endOfStack = true;
+        break;
       default:
         // Personality routine returned an unknown result code.
         _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
@@ -1133,9 +1147,14 @@ extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
 __gnu_unwind_frame(_Unwind_Exception *exception_object,
                    struct _Unwind_Context *context) {
   unw_cursor_t *cursor = (unw_cursor_t *)context;
-  if (__unw_step(cursor) != UNW_STEP_SUCCESS)
+  switch (__unw_step(cursor)) {
+  case UNW_STEP_SUCCESS:
+    return _URC_OK;
+  case UNW_STEP_END:
+    return _URC_END_OF_STACK;
+  default:
     return _URC_FAILURE;
-  return _URC_OK;
+  }
 }
 
 #endif  // defined(_LIBUNWIND_ARM_EHABI)


        


More information about the libcxx-commits mailing list