ART: Correctly handle an abort from an unattached thread
Libbase may be shared with other platform components. In that case,
if the aborting thread is attached to the runtime, ART will print
its usual dump to be helpful.
If the thread is unattached, this must not be done as it would
violate mutex invariants.
Bug: 135056249
Test: m test-art-host-gtest-runtime_test
Change-Id: I61c3df5fdbc8ddaf279f39dc653738016986dcd9
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 22b76d2..821c75d 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -82,7 +82,9 @@
// Avoid recursive death.
level == kAbortLock ||
// Locks at the absolute top of the stack can be locked at any time.
- level == kTopLockLevel) << level;
+ level == kTopLockLevel ||
+ // The unexpected signal handler may be catching signals from any thread.
+ level == kUnexpectedSignalLock) << level;
}
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 93ba622..3ad0504 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -610,6 +610,15 @@
#endif
}
+ // May be coming from an unattached thread.
+ if (Thread::Current() == nullptr) {
+ Runtime* current = Runtime::Current();
+ if (current != nullptr && current->IsStarted() && !current->IsShuttingDown(nullptr)) {
+ abort();
+ UNREACHABLE();
+ }
+ }
+
{
// Ensure that we don't have multiple threads trying to abort at once,
// which would result in significantly worse diagnostics.
diff --git a/runtime/runtime_test.cc b/runtime/runtime_test.cc
index 282e430..3fe281b 100644
--- a/runtime/runtime_test.cc
+++ b/runtime/runtime_test.cc
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+#include "common_runtime_test.h"
+
+#include <thread>
+
#include "android-base/logging.h"
#include "base/locks.h"
#include "base/mutex.h"
-#include "common_runtime_test.h"
#include "runtime.h"
#include "thread-current-inl.h"
@@ -54,4 +57,22 @@
}, kDeathRegex);
}
+TEST_F(RuntimeTest, AbortFromUnattachedThread) {
+ // This assumes the test is run single-threaded: do not start the runtime to avoid daemon threads.
+
+ constexpr const char* kDeathRegex = "Going down";
+ ASSERT_EXIT({
+ // The regex only works if we can ensure output goes to stderr.
+ android::base::SetLogger(android::base::StderrLogger);
+
+ Thread::Current()->TransitionFromSuspendedToRunnable();
+ runtime_->Start();
+
+ std::thread t([]() {
+ LOG(FATAL) << "Going down";
+ });
+ t.join();
+ }, ::testing::KilledBySignal(SIGABRT), kDeathRegex);
+}
+
} // namespace art