1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "lock_count_data.h"
18 
19 #include <algorithm>
20 #include <string>
21 
22 #include "android-base/logging.h"
23 #include "mirror/object-inl.h"
24 #include "thread.h"
25 
26 namespace art {
27 
AddMonitor(Thread * self,mirror::Object * obj)28 void LockCountData::AddMonitor(Thread* self, mirror::Object* obj) {
29   if (obj == nullptr) {
30     return;
31   }
32 
33   // If there's an error during enter, we won't have locked the monitor. So check there's no
34   // exception.
35   if (self->IsExceptionPending()) {
36     return;
37   }
38 
39   if (monitors_ == nullptr) {
40     monitors_.reset(new std::vector<mirror::Object*>());
41   }
42   monitors_->push_back(obj);
43 }
44 
RemoveMonitorOrThrow(Thread * self,const mirror::Object * obj)45 void LockCountData::RemoveMonitorOrThrow(Thread* self, const mirror::Object* obj) {
46   if (obj == nullptr) {
47     return;
48   }
49   bool found_object = false;
50   if (monitors_ != nullptr) {
51     // We need to remove one pointer to ref, as duplicates are used for counting recursive locks.
52     // We arbitrarily choose the first one.
53     auto it = std::find(monitors_->begin(), monitors_->end(), obj);
54     if (it != monitors_->end()) {
55       monitors_->erase(it);
56       found_object = true;
57     }
58   }
59   if (!found_object) {
60     // The object wasn't found. Time for an IllegalMonitorStateException.
61     // The order here isn't fully clear. Assume that any other pending exception is swallowed.
62     // TODO: Maybe make already pending exception a suppressed exception.
63     self->ClearException();
64     self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;",
65                              "did not lock monitor on object of type '%s' before unlocking",
66                              const_cast<mirror::Object*>(obj)->PrettyTypeOf().c_str());
67   }
68 }
69 
70 // Helper to unlock a monitor. Must be NO_THREAD_SAFETY_ANALYSIS, as we can't statically show
71 // that the object was locked.
MonitorExitHelper(Thread * self,mirror::Object * obj)72 void MonitorExitHelper(Thread* self, mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS {
73   DCHECK(self != nullptr);
74   DCHECK(obj != nullptr);
75   obj->MonitorExit(self);
76 }
77 
CheckAllMonitorsReleasedOrThrow(Thread * self)78 bool LockCountData::CheckAllMonitorsReleasedOrThrow(Thread* self) {
79   DCHECK(self != nullptr);
80   if (monitors_ != nullptr) {
81     if (!monitors_->empty()) {
82       // There may be an exception pending, if the method is terminating abruptly. Clear it.
83       // TODO: Should we add this as a suppressed exception?
84       self->ClearException();
85 
86       // OK, there are monitors that are still locked. To enforce structured locking (and avoid
87       // deadlocks) we unlock all of them before we raise the IllegalMonitorState exception.
88       for (mirror::Object* obj : *monitors_) {
89         MonitorExitHelper(self, obj);
90         // If this raised an exception, ignore. TODO: Should we add this as suppressed
91         // exceptions?
92         if (self->IsExceptionPending()) {
93           self->ClearException();
94         }
95       }
96       // Raise an exception, just give the first object as the sample.
97       mirror::Object* first = (*monitors_)[0];
98       self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;",
99                                "did not unlock monitor on object of type '%s'",
100                                mirror::Object::PrettyTypeOf(first).c_str());
101 
102       // To make sure this path is not triggered again, clean out the monitors.
103       monitors_->clear();
104 
105       return false;
106     }
107   }
108   return true;
109 }
110 
111 }  // namespace art
112