diff options
-rw-r--r-- | runtime/base/mutex-inl.h | 4 | ||||
-rw-r--r-- | runtime/runtime.cc | 9 | ||||
-rw-r--r-- | runtime/runtime_test.cc | 23 |
3 files changed, 34 insertions, 2 deletions
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index 22b76d231b..821c75d9b3 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -82,7 +82,9 @@ static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALY // 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 93ba622b04..3ad0504405 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -610,6 +610,15 @@ void Runtime::Abort(const char* msg) { #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 282e43071e..3fe281bd5f 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 @@ TEST_F(RuntimeTest, AbortWithThreadSuspendCountLockHeld) { }, 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 |