xref: /aosp_15_r20/art/dex2oat/interpreter/unstarted_runtime_transaction_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2024 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 "interpreter/unstarted_runtime_test.h"
18 
19 #include "class_root-inl.h"
20 #include "common_transaction_test.h"
21 #include "dex/descriptors_names.h"
22 #include "interpreter/interpreter_common.h"
23 #include "handle.h"
24 #include "handle_scope-inl.h"
25 #include "mirror/class-inl.h"
26 
27 namespace art HIDDEN {
28 namespace interpreter {
29 
30 class UnstartedRuntimeTransactionTest : public CommonTransactionTestBase<UnstartedRuntimeTestBase> {
31  protected:
32   // Prepare for aborts. Aborts assume that the exception class is already resolved, as the
33   // loading code doesn't work under transactions.
PrepareForAborts()34   void PrepareForAborts() REQUIRES_SHARED(Locks::mutator_lock_) {
35     ObjPtr<mirror::Object> result =
36         FindClass(kTransactionAbortErrorDescriptor, ScopedNullHandle<mirror::ClassLoader>());
37     CHECK(result != nullptr);
38   }
39 };
40 
TEST_F(UnstartedRuntimeTransactionTest,ToLowerUpper)41 TEST_F(UnstartedRuntimeTransactionTest, ToLowerUpper) {
42   Thread* self = Thread::Current();
43   ScopedObjectAccess soa(self);
44   UniqueDeoptShadowFramePtr tmp = CreateShadowFrame(10, nullptr, 0);
45 
46   PrepareForAborts();
47 
48   for (uint32_t i = 128; i < 256; ++i) {
49     {
50       JValue result;
51       tmp->SetVReg(0, static_cast<int32_t>(i));
52       EnterTransactionMode();
53       UnstartedCharacterToLowerCase(self, tmp.get(), &result, 0);
54       ASSERT_TRUE(IsTransactionAborted());
55       ExitTransactionMode();
56       ASSERT_TRUE(self->IsExceptionPending());
57     }
58     {
59       JValue result;
60       tmp->SetVReg(0, static_cast<int32_t>(i));
61       EnterTransactionMode();
62       UnstartedCharacterToUpperCase(self, tmp.get(), &result, 0);
63       ASSERT_TRUE(IsTransactionAborted());
64       ExitTransactionMode();
65       ASSERT_TRUE(self->IsExceptionPending());
66     }
67   }
68   for (uint64_t i = 256; i <= std::numeric_limits<uint32_t>::max(); i <<= 1) {
69     {
70       JValue result;
71       tmp->SetVReg(0, static_cast<int32_t>(i));
72       EnterTransactionMode();
73       UnstartedCharacterToLowerCase(self, tmp.get(), &result, 0);
74       ASSERT_TRUE(IsTransactionAborted());
75       ExitTransactionMode();
76       ASSERT_TRUE(self->IsExceptionPending());
77     }
78     {
79       JValue result;
80       tmp->SetVReg(0, static_cast<int32_t>(i));
81       EnterTransactionMode();
82       UnstartedCharacterToUpperCase(self, tmp.get(), &result, 0);
83       ASSERT_TRUE(IsTransactionAborted());
84       ExitTransactionMode();
85       ASSERT_TRUE(self->IsExceptionPending());
86     }
87   }
88 }
89 
TEST_F(UnstartedRuntimeTransactionTest,ThreadLocalGet)90 TEST_F(UnstartedRuntimeTransactionTest, ThreadLocalGet) {
91   Thread* self = Thread::Current();
92   ScopedObjectAccess soa(self);
93   UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, nullptr, 0);
94 
95   // Negative test.
96   PrepareForAborts();
97 
98   // Just use a method in Class.
99   ObjPtr<mirror::Class> class_class = GetClassRoot<mirror::Class>();
100   ArtMethod* caller_method =
101       &*class_class->GetDeclaredMethods(class_linker_->GetImagePointerSize()).begin();
102   UniqueDeoptShadowFramePtr caller_frame = CreateShadowFrame(10, caller_method, 0);
103   shadow_frame->SetLink(caller_frame.get());
104 
105   JValue result;
106   EnterTransactionMode();
107   UnstartedThreadLocalGet(self, shadow_frame.get(), &result, 0);
108   ASSERT_TRUE(IsTransactionAborted());
109   ExitTransactionMode();
110   ASSERT_TRUE(self->IsExceptionPending());
111   self->ClearException();
112 
113   shadow_frame->ClearLink();
114 }
115 
TEST_F(UnstartedRuntimeTransactionTest,ThreadCurrentThread)116 TEST_F(UnstartedRuntimeTransactionTest, ThreadCurrentThread) {
117   Thread* self = Thread::Current();
118   ScopedObjectAccess soa(self);
119   UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, nullptr, 0);
120 
121   // Negative test. In general, currentThread should fail (as we should not leak a peer that will
122   // be recreated at runtime).
123   PrepareForAborts();
124 
125   JValue result;
126   EnterTransactionMode();
127   UnstartedThreadCurrentThread(self, shadow_frame.get(), &result, 0);
128   ASSERT_TRUE(IsTransactionAborted());
129   ExitTransactionMode();
130   ASSERT_TRUE(self->IsExceptionPending());
131   self->ClearException();
132 }
133 
134 class UnstartedClassForNameTransactionTest : public UnstartedRuntimeTransactionTest {
135  public:
136   template <typename T>
RunTest(T && runner,bool should_succeed)137   void RunTest(T&& runner, bool should_succeed) {
138     Thread* self = Thread::Current();
139     ScopedObjectAccess soa(self);
140 
141     // Ensure that Class is initialized.
142     CHECK(GetClassRoot<mirror::Class>()->IsInitialized());
143 
144     // A selection of classes from different core classpath components.
145     constexpr const char* kTestCases[] = {
146         "java.net.CookieManager",  // From libcore.
147         "dalvik.system.ClassExt",  // From libart.
148     };
149 
150     // For transaction mode, we cannot load any classes, as the pre-fence initialization of
151     // classes isn't transactional. Load them ahead of time.
152     for (const char* name : kTestCases) {
153       FindClass(DotToDescriptor(name).c_str(), ScopedNullHandle<mirror::ClassLoader>());
154       CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
155     }
156 
157     if (!should_succeed) {
158       // Negative test. In general, currentThread should fail (as we should not leak a peer that will
159       // be recreated at runtime).
160       PrepareForAborts();
161     }
162 
163     JValue result;
164     UniqueDeoptShadowFramePtr shadow_frame = CreateShadowFrame(10, nullptr, 0);
165 
166     for (const char* name : kTestCases) {
167       EnterTransactionMode();
168 
169       ObjPtr<mirror::String> name_string = mirror::String::AllocFromModifiedUtf8(self, name);
170       CHECK(name_string != nullptr);
171       CHECK(!self->IsExceptionPending());
172 
173       runner(self, shadow_frame.get(), name_string, &result);
174 
175       if (should_succeed) {
176         CHECK(!self->IsExceptionPending()) << name << " " << self->GetException()->Dump();
177         CHECK(result.GetL() != nullptr) << name;
178       } else {
179         CHECK(self->IsExceptionPending()) << name;
180         ASSERT_TRUE(IsTransactionAborted());
181         self->ClearException();
182       }
183 
184       ExitTransactionMode();
185     }
186   }
187 };
188 
TEST_F(UnstartedClassForNameTransactionTest,ClassForNameLongWithClassLoader)189 TEST_F(UnstartedClassForNameTransactionTest, ClassForNameLongWithClassLoader) {
190   Thread* self = Thread::Current();
191   ScopedObjectAccess soa(self);
192 
193   StackHandleScope<1> hs(self);
194   Handle<mirror::ClassLoader> boot_cp = hs.NewHandle(GetBootClassLoader());
195 
196   auto runner = [&](Thread* th,
197                     ShadowFrame* shadow_frame,
198                     ObjPtr<mirror::String> name,
199                     JValue* result)
200       REQUIRES_SHARED(Locks::mutator_lock_) {
201     shadow_frame->SetVRegReference(0, name);
202     shadow_frame->SetVReg(1, 0);
203     shadow_frame->SetVRegReference(2, boot_cp.Get());
204     UnstartedClassForNameLong(th, shadow_frame, result, 0);
205   };
206   RunTest(runner, /*should_succeed=*/ true);
207 }
208 
TEST_F(UnstartedClassForNameTransactionTest,ClassForNameLongWithClassLoaderFail)209 TEST_F(UnstartedClassForNameTransactionTest, ClassForNameLongWithClassLoaderFail) {
210   Thread* self = Thread::Current();
211   ScopedObjectAccess soa(self);
212 
213   StackHandleScope<2> hs(self);
214   jobject path_jobj = class_linker_->CreatePathClassLoader(self, {});
215   ASSERT_TRUE(path_jobj != nullptr);
216   Handle<mirror::ClassLoader> path_cp = hs.NewHandle<mirror::ClassLoader>(
217       self->DecodeJObject(path_jobj)->AsClassLoader());
218 
219   auto runner = [&](Thread* th,
220                     ShadowFrame* shadow_frame,
221                     ObjPtr<mirror::String> name,
222                     JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
223     shadow_frame->SetVRegReference(0, name);
224     shadow_frame->SetVReg(1, 0);
225     shadow_frame->SetVRegReference(2, path_cp.Get());
226     UnstartedClassForNameLong(th, shadow_frame, result, 0);
227   };
228   RunTest(runner, /*should_succeed=*/ false);
229 }
230 
231 }  // namespace interpreter
232 }  // namespace art
233