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