summaryrefslogtreecommitdiff
path: root/runtime/interpreter/interpreter_switch_impl-inl.h
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2019-05-29 18:30:33 -0700
committer Alex Light <allight@google.com> 2019-05-30 21:26:44 +0000
commitbbb1adb9e4dbd6284a3758da521f017d64d8056f (patch)
tree80df8e4f68500d45783512fa8b4207135484e192 /runtime/interpreter/interpreter_switch_impl-inl.h
parent617b3a23390922be67c1b72e23c0d373149bb457 (diff)
Ensure non-standard returns release monitors
We were incorrectly failing to unlock monitors that were acquired by a frame when the frame is popped off the stack in a non-standard manner. This can lead to monitors having an incorrect count and being impossible for any other thread to lock. (cherry picked from commit 7b42b42a41c18d83fc3262d9fa4461d6afe74452) Test: ./test.py --host Bug: 133901254 Merged-In: I2efbb8854dd5530c66d780f6853ec6e05a69c83b Change-Id: I2efbb8854dd5530c66d780f6853ec6e05a69c83b
Diffstat (limited to 'runtime/interpreter/interpreter_switch_impl-inl.h')
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h39
1 files changed, 39 insertions, 0 deletions
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index aec2aa2564..36cfee418e 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -20,19 +20,24 @@
#include "interpreter_switch_impl.h"
#include "base/enums.h"
+#include "base/globals.h"
#include "base/memory_tool.h"
#include "base/quasi_atomic.h"
#include "dex/dex_file_types.h"
#include "dex/dex_instruction_list.h"
#include "experimental_flags.h"
+#include "handle_scope.h"
#include "interpreter_common.h"
+#include "interpreter/shadow_frame.h"
#include "jit/jit-inl.h"
#include "jvalue-inl.h"
#include "mirror/string-alloc-inl.h"
+#include "mirror/throwable.h"
#include "nth_caller_visitor.h"
#include "safe_math.h"
#include "shadow_frame-inl.h"
#include "thread.h"
+#include "verifier/method_verifier.h"
namespace art {
namespace interpreter {
@@ -49,12 +54,46 @@ namespace interpreter {
template<bool do_access_check, bool transaction_active>
class InstructionHandler {
public:
+ template <bool kMonitorCounting>
+ static NO_INLINE void UnlockHeldMonitors(Thread* self, ShadowFrame* shadow_frame)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(shadow_frame->GetForcePopFrame());
+ // Unlock all monitors.
+ if (kMonitorCounting && shadow_frame->GetMethod()->MustCountLocks()) {
+ // Get the monitors from the shadow-frame monitor-count data.
+ shadow_frame->GetLockCountData().VisitMonitors(
+ [&](mirror::Object** obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Since we don't use the 'obj' pointer after the DoMonitorExit everything should be fine
+ // WRT suspension.
+ DoMonitorExit<do_assignability_check>(self, shadow_frame, *obj);
+ });
+ } else {
+ std::vector<verifier::MethodVerifier::DexLockInfo> locks;
+ verifier::MethodVerifier::FindLocksAtDexPc(shadow_frame->GetMethod(),
+ shadow_frame->GetDexPC(),
+ &locks,
+ Runtime::Current()->GetTargetSdkVersion());
+ for (const auto& reg : locks) {
+ if (UNLIKELY(reg.dex_registers.empty())) {
+ LOG(ERROR) << "Unable to determine reference locked by "
+ << shadow_frame->GetMethod()->PrettyMethod() << " at pc "
+ << shadow_frame->GetDexPC();
+ } else {
+ DoMonitorExit<do_assignability_check>(
+ self, shadow_frame, shadow_frame->GetVRegReference(*reg.dex_registers.begin()));
+ }
+ }
+ }
+ }
+
ALWAYS_INLINE WARN_UNUSED bool CheckForceReturn()
REQUIRES_SHARED(Locks::mutator_lock_) {
if (UNLIKELY(shadow_frame.GetForcePopFrame())) {
DCHECK(PrevFrameWillRetry(self, shadow_frame))
<< "Pop frame forced without previous frame ready to retry instruction!";
DCHECK(Runtime::Current()->AreNonStandardExitsEnabled());
+ UnlockHeldMonitors<do_assignability_check>(self, &shadow_frame);
+ DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame);
if (UNLIKELY(NeedsMethodExitEvent(instrumentation))) {
SendMethodExitEvents(self,
instrumentation,