ART: Stash any exception before dumping a stack

Dumping a managed stack entails dumping held locks, in the process
of which the verifier will be run. The verifier works under the
assumption that there were no exceptions when started. This
assumption is violated for example on certain JNI aborts.

The solution is to stash any pending exception before dumping the
stack, and re-installing it afterwards.

Bug: 17669899

(cherry picked from commit d87bc135dba41f0f21cf0018a3b2cb46809890d7)

Change-Id: Ic44780bad90a8e1ba80858c807e2bef3bf6651c6
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b0c8fe1..d573a3f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -947,10 +947,27 @@
 }
 
 void Thread::DumpJavaStack(std::ostream& os) const {
+  // Dumping the Java stack involves the verifier for locks. The verifier operates under the
+  // assumption that there is no exception pending on entry. Thus, stash any pending exception.
+  // TODO: Find a way to avoid const_cast.
+  StackHandleScope<1> scope(const_cast<Thread*>(this));
+  Handle<mirror::Throwable> exc;
+  ThrowLocation exc_location;
+  bool have_exception = false;
+  if (IsExceptionPending()) {
+    exc = scope.NewHandle(GetException(&exc_location));
+    const_cast<Thread*>(this)->ClearException();
+    have_exception = true;
+  }
+
   std::unique_ptr<Context> context(Context::Create());
   StackDumpVisitor dumper(os, const_cast<Thread*>(this), context.get(),
                           !tls32_.throwing_OutOfMemoryError);
   dumper.WalkStack();
+
+  if (have_exception) {
+    const_cast<Thread*>(this)->SetException(exc_location, exc.Get());
+  }
 }
 
 void Thread::DumpStack(std::ostream& os) const {