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