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