• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "runtime/include/exceptions.h"
17 
18 #include <libpandabase/utils/cframe_layout.h>
19 
20 #include "runtime/bridge/bridge.h"
21 #include "runtime/deoptimization.h"
22 #include "runtime/entrypoints/entrypoints.h"
23 #include "runtime/include/coretypes/string.h"
24 #include "runtime/include/object_header-inl.h"
25 #include "runtime/include/runtime.h"
26 #include "runtime/include/stack_walker.h"
27 #include "runtime/mem/vm_handle.h"
28 #include "libpandabase/utils/asan_interface.h"
29 #include "libpandabase/utils/logger.h"
30 #include "libpandabase/utils/utf.h"
31 #include "libpandafile/class_data_accessor-inl.h"
32 #include "libpandafile/method_data_accessor-inl.h"
33 #include "events/events.h"
34 #include "runtime/handle_base-inl.h"
35 
36 namespace panda {
37 
ThrowException(const LanguageContext & ctx,ManagedThread * thread,const uint8_t * mutf8_name,const uint8_t * mutf8_msg)38 void ThrowException(const LanguageContext &ctx, ManagedThread *thread, const uint8_t *mutf8_name,
39                     const uint8_t *mutf8_msg)
40 {
41     ctx.ThrowException(thread, mutf8_name, mutf8_msg);
42 }
43 
GetLanguageContext(ManagedThread * thread)44 static LanguageContext GetLanguageContext(ManagedThread *thread)
45 {
46     ASSERT(thread != nullptr);
47     return thread->GetVM()->GetLanguageContext();
48 }
49 
ThrowNullPointerException()50 void ThrowNullPointerException()
51 {
52     auto *thread = ManagedThread::GetCurrent();
53     auto ctx = GetLanguageContext(thread);
54     ThrowNullPointerException(ctx, thread);
55 }
56 
ThrowNullPointerException(const LanguageContext & ctx,ManagedThread * thread)57 void ThrowNullPointerException(const LanguageContext &ctx, ManagedThread *thread)
58 {
59     ThrowException(ctx, thread, ctx.GetNullPointerExceptionClassDescriptor(), nullptr);
60 }
61 
ThrowStackOverflowException(ManagedThread * thread)62 void ThrowStackOverflowException(ManagedThread *thread)
63 {
64     auto ctx = GetLanguageContext(thread);
65     ctx.ThrowStackOverflowException(thread);
66 }
67 
ThrowArrayIndexOutOfBoundsException(coretypes::array_ssize_t idx,coretypes::array_size_t length)68 void ThrowArrayIndexOutOfBoundsException(coretypes::array_ssize_t idx, coretypes::array_size_t length)
69 {
70     auto *thread = ManagedThread::GetCurrent();
71     auto ctx = GetLanguageContext(thread);
72     ThrowArrayIndexOutOfBoundsException(idx, length, ctx, thread);
73 }
74 
ThrowArrayIndexOutOfBoundsException(coretypes::array_ssize_t idx,coretypes::array_size_t length,const LanguageContext & ctx,ManagedThread * thread)75 void ThrowArrayIndexOutOfBoundsException(coretypes::array_ssize_t idx, coretypes::array_size_t length,
76                                          const LanguageContext &ctx, ManagedThread *thread)
77 {
78     PandaString msg;
79     msg = "idx = " + ToPandaString(idx) + "; length = " + ToPandaString(length);
80 
81     ThrowException(ctx, thread, ctx.GetArrayIndexOutOfBoundsExceptionClassDescriptor(),
82                    utf::CStringAsMutf8(msg.c_str()));
83 }
84 
ThrowIndexOutOfBoundsException(coretypes::array_ssize_t idx,coretypes::array_ssize_t length)85 void ThrowIndexOutOfBoundsException(coretypes::array_ssize_t idx, coretypes::array_ssize_t length)
86 {
87     auto *thread = ManagedThread::GetCurrent();
88     auto ctx = GetLanguageContext(thread);
89 
90     PandaString msg;
91     msg = "idx = " + ToPandaString(idx) + "; length = " + ToPandaString(length);
92 
93     ThrowException(ctx, thread, ctx.GetIndexOutOfBoundsExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
94 }
95 
ThrowIllegalStateException(const PandaString & msg)96 void ThrowIllegalStateException(const PandaString &msg)
97 {
98     auto *thread = ManagedThread::GetCurrent();
99     auto ctx = GetLanguageContext(thread);
100     ThrowException(ctx, thread, ctx.GetIllegalStateExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
101 }
102 
ThrowStringIndexOutOfBoundsException(coretypes::array_ssize_t idx,coretypes::array_size_t length)103 void ThrowStringIndexOutOfBoundsException(coretypes::array_ssize_t idx, coretypes::array_size_t length)
104 {
105     auto *thread = ManagedThread::GetCurrent();
106     auto ctx = GetLanguageContext(thread);
107 
108     PandaString msg;
109     msg = "idx = " + ToPandaString(idx) + "; length = " + ToPandaString(length);
110 
111     ThrowException(ctx, thread, ctx.GetStringIndexOutOfBoundsExceptionClassDescriptor(),
112                    utf::CStringAsMutf8(msg.c_str()));
113 }
114 
ThrowNegativeArraySizeException(coretypes::array_ssize_t size)115 void ThrowNegativeArraySizeException(coretypes::array_ssize_t size)
116 {
117     auto *thread = ManagedThread::GetCurrent();
118     auto ctx = GetLanguageContext(thread);
119 
120     PandaString msg;
121     msg = "size = " + ToPandaString(size);
122 
123     ThrowException(ctx, thread, ctx.GetNegativeArraySizeExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
124 }
125 
ThrowNegativeArraySizeException(const PandaString & msg)126 void ThrowNegativeArraySizeException(const PandaString &msg)
127 {
128     auto *thread = ManagedThread::GetCurrent();
129     auto ctx = GetLanguageContext(thread);
130     ThrowException(ctx, thread, ctx.GetNegativeArraySizeExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
131 }
132 
ThrowArithmeticException()133 void ThrowArithmeticException()
134 {
135     auto *thread = ManagedThread::GetCurrent();
136     auto ctx = GetLanguageContext(thread);
137     ThrowException(ctx, thread, ctx.GetArithmeticExceptionClassDescriptor(), utf::CStringAsMutf8("/ by zero"));
138 }
139 
ThrowClassCastException(const Class * dst_type,const Class * src_type)140 void ThrowClassCastException(const Class *dst_type, const Class *src_type)
141 {
142     auto *thread = ManagedThread::GetCurrent();
143     auto ctx = GetLanguageContext(thread);
144 
145     PandaString msg;
146     msg = src_type->GetName() + " cannot be cast to " + dst_type->GetName();
147 
148     ThrowException(ctx, thread, ctx.GetClassCastExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
149 }
150 
ThrowAbstractMethodError(const Method * method)151 void ThrowAbstractMethodError(const Method *method)
152 {
153     auto *thread = ManagedThread::GetCurrent();
154     auto ctx = GetLanguageContext(thread);
155 
156     PandaString msg;
157     msg = "abstract method \"" + method->GetClass()->GetName() + ".";
158     msg += utf::Mutf8AsCString(method->GetName().data);
159     msg += "\"";
160 
161     ThrowException(ctx, thread, ctx.GetAbstractMethodErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
162 }
163 
ThrowIncompatibleClassChangeErrorForMethodConflict(const Method * method)164 void ThrowIncompatibleClassChangeErrorForMethodConflict(const Method *method)
165 {
166     auto *thread = ManagedThread::GetCurrent();
167     auto ctx = GetLanguageContext(thread);
168 
169     PandaString msg;
170     msg = "Conflicting default method implementations \"" + method->GetClass()->GetName() + ".";
171     msg += utf::Mutf8AsCString(method->GetName().data);
172     msg += "\"";
173 
174     ThrowException(ctx, thread, ctx.GetIncompatibleClassChangeErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
175 }
176 
ThrowArrayStoreException(const Class * array_class,const Class * element_class)177 void ThrowArrayStoreException(const Class *array_class, const Class *element_class)
178 {
179     PandaStringStream ss;
180     ss << element_class->GetName() << " cannot be stored in an array of type " << array_class->GetName();
181     ThrowArrayStoreException(ss.str());
182 }
183 
ThrowArrayStoreException(const PandaString & msg)184 void ThrowArrayStoreException(const PandaString &msg)
185 {
186     auto *thread = ManagedThread::GetCurrent();
187     auto ctx = GetLanguageContext(thread);
188 
189     ThrowException(ctx, thread, ctx.GetArrayStoreExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
190 }
191 
ThrowRuntimeException(const PandaString & msg)192 void ThrowRuntimeException(const PandaString &msg)
193 {
194     auto *thread = ManagedThread::GetCurrent();
195     auto ctx = GetLanguageContext(thread);
196 
197     ThrowException(ctx, thread, ctx.GetRuntimeExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
198 }
199 
ThrowIllegalArgumentException(const PandaString & msg)200 void ThrowIllegalArgumentException(const PandaString &msg)
201 {
202     auto *thread = ManagedThread::GetCurrent();
203     auto ctx = GetLanguageContext(thread);
204 
205     ThrowException(ctx, thread, ctx.GetIllegalArgumentExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
206 }
207 
ThrowClassCircularityError(const PandaString & class_name,const LanguageContext & ctx)208 void ThrowClassCircularityError(const PandaString &class_name, const LanguageContext &ctx)
209 {
210     auto *thread = ManagedThread::GetCurrent();
211     PandaString msg = "Class or interface \"" + class_name + "\" is its own superclass or superinterface";
212     ThrowException(ctx, thread, ctx.GetClassCircularityErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
213 }
214 
215 /**
216  * The function finds the corresponding catch block for the exception in the thread.
217  * The function uses thread as an exception storage because:
218  *  1. thread's exception is a GC root
219  *  2. we cannot use Handl;eScope her ebecause the function is [[noreturn]]
220  */
221 // NOLINTNEXTLINE(google-runtime-references)
FindCatchBlockInCFrames(ManagedThread * thread,StackWalker * stack,Frame * orig_frame)222 NO_ADDRESS_SANITIZE void FindCatchBlockInCFrames(ManagedThread *thread, StackWalker *stack, Frame *orig_frame)
223 {
224     auto next_frame = stack->GetNextFrame();
225     for (; stack->HasFrame(); stack->NextFrame(), next_frame = stack->GetNextFrame()) {
226         LOG(DEBUG, INTEROP) << "Search for the catch block in " << stack->GetMethod()->GetFullName();
227 
228         auto pc = stack->GetBytecodePc();
229         auto *method = stack->GetMethod();
230         ASSERT(method != nullptr);
231         uint32_t pc_offset = method->FindCatchBlock(thread->GetException()->ClassAddr<Class>(), pc);
232 
233         if (pc_offset != panda_file::INVALID_OFFSET) {
234             if (orig_frame != nullptr) {
235                 FreeFrame(orig_frame);
236             }
237 
238             LOG(DEBUG, INTEROP) << "Catch block is found in " << stack->GetMethod()->GetFullName();
239             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
240             Deoptimize(stack, method->GetInstructions() + pc_offset);
241             UNREACHABLE();
242         }
243 
244         thread->GetVM()->HandleReturnFrame();
245 
246         if (!next_frame.IsCFrame()) {
247             if (orig_frame != nullptr) {
248                 FreeFrame(orig_frame);
249             }
250             thread->SetCurrentFrame(next_frame.GetIFrame());
251             LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame isn't CFrame";
252             DropCompiledFrame(stack);
253             UNREACHABLE();
254         }
255 
256         if (next_frame.GetCFrame().IsNative()) {
257             if (orig_frame != nullptr) {
258                 FreeFrame(orig_frame);
259             }
260             LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is NATIVE";
261             DropCompiledFrame(stack);
262             UNREACHABLE();
263         }
264 
265         if (method->IsStaticConstructor()) {
266             if (orig_frame != nullptr) {
267                 FreeFrame(orig_frame);
268             }
269             LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is StaticConstructor";
270             DropCompiledFrame(stack);
271             UNREACHABLE();
272         }
273 
274         if (!stack->IsInlined()) {
275             auto prev = stack->GetCFrame().GetPrevFrame();
276             if (stack->GetBoundaryFrameMethod<FrameKind::COMPILER>(prev) == FrameBridgeKind::BYPASS) {
277                 /**
278                  * There is bypass bridge and current frame is not inlined, hence we are going to exit compiled
279                  * function. Dynamic languages may do c2c call through runtime, so it's necessary to return to exit
280                  * active function properly.
281                  */
282                 if (orig_frame != nullptr) {
283                     FreeFrame(orig_frame);
284                 }
285                 LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is caller's cframe";
286                 DropCompiledFrame(stack);
287                 UNREACHABLE();
288             }
289         }
290     }
291 
292     if (next_frame.IsValid()) {
293         LOG(DEBUG, INTEROP) << "Exception " << thread->GetException()->ClassAddr<Class>()->GetName() << " isn't found";
294         EVENT_METHOD_EXIT(stack->GetMethod()->GetFullName(), events::MethodExitKind::COMPILED,
295                           thread->RecordMethodExit());
296         thread->GetVM()->HandleReturnFrame();
297         DropCompiledFrame(stack);
298     }
299     UNREACHABLE();
300 }
301 
302 /**
303  * The function finds the corresponding catch block for the exception in the thread.
304  * The function uses thread as an exception storage because:
305  *  1. thread's exception is a GC root
306  *  2. we cannot use Handl;eScope her ebecause the function is [[noreturn]]
307  */
FindCatchBlockInCallStack(ManagedThread * thread)308 NO_ADDRESS_SANITIZE void FindCatchBlockInCallStack(ManagedThread *thread)
309 {
310     auto stack = StackWalker::Create(thread);
311     auto orig_frame = stack.GetIFrame();
312     ASSERT(!stack.IsCFrame());
313     LOG(DEBUG, INTEROP) << "Enter in FindCatchBlockInCallStack for " << orig_frame->GetMethod()->GetFullName();
314     // Exception will be handled in the Method::Invoke's caller
315     if (orig_frame->IsInvoke()) {
316         return;
317     }
318 
319     stack.NextFrame();
320 
321     // NATIVE frames can handle exceptions as well
322     if (!stack.HasFrame() || !stack.IsCFrame() || stack.GetCFrame().IsNative()) {
323         return;
324     }
325     FindCatchBlockInCFrames(thread, &stack, orig_frame);
326 }
327 
ThrowFileNotFoundException(const PandaString & msg)328 void ThrowFileNotFoundException(const PandaString &msg)
329 {
330     auto *thread = ManagedThread::GetCurrent();
331     auto ctx = GetLanguageContext(thread);
332 
333     ThrowException(ctx, thread, ctx.GetFileNotFoundExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
334 }
335 
ThrowIOException(const PandaString & msg)336 void ThrowIOException(const PandaString &msg)
337 {
338     auto *thread = ManagedThread::GetCurrent();
339     auto ctx = GetLanguageContext(thread);
340 
341     ThrowException(ctx, thread, ctx.GetIOExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
342 }
343 
ThrowIllegalAccessException(const PandaString & msg)344 void ThrowIllegalAccessException(const PandaString &msg)
345 {
346     auto *thread = ManagedThread::GetCurrent();
347     auto ctx = GetLanguageContext(thread);
348 
349     ThrowException(ctx, thread, ctx.GetIllegalAccessExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
350 }
351 
ThrowOutOfMemoryError(ManagedThread * thread,const PandaString & msg)352 void ThrowOutOfMemoryError(ManagedThread *thread, const PandaString &msg)
353 {
354     auto ctx = GetLanguageContext(thread);
355 
356     if (thread->IsThrowingOOM()) {
357         thread->SetUsePreAllocObj(true);
358     }
359 
360     thread->SetThrowingOOM(true);
361     ThrowException(ctx, thread, ctx.GetOutOfMemoryErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
362     thread->SetThrowingOOM(false);
363 }
364 
ThrowOutOfMemoryError(const PandaString & msg)365 void ThrowOutOfMemoryError(const PandaString &msg)
366 {
367     auto *thread = ManagedThread::GetCurrent();
368     ThrowOutOfMemoryError(thread, msg);
369 }
370 
ThrowUnsupportedOperationException()371 void ThrowUnsupportedOperationException()
372 {
373     auto *thread = ManagedThread::GetCurrent();
374     auto ctx = GetLanguageContext(thread);
375     ThrowException(ctx, thread, ctx.GetUnsupportedOperationExceptionClassDescriptor(), nullptr);
376 }
377 
ThrowVerificationException(const PandaString & msg)378 void ThrowVerificationException(const PandaString &msg)
379 {
380     auto *thread = ManagedThread::GetCurrent();
381     auto ctx = GetLanguageContext(thread);
382 
383     ThrowException(ctx, thread, ctx.GetVerifyErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
384 }
385 
ThrowVerificationException(const LanguageContext & ctx,const PandaString & msg)386 void ThrowVerificationException(const LanguageContext &ctx, const PandaString &msg)
387 {
388     auto *thread = ManagedThread::GetCurrent();
389 
390     ThrowException(ctx, thread, ctx.GetVerifyErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
391 }
392 
ThrowInstantiationError(const PandaString & msg)393 void ThrowInstantiationError(const PandaString &msg)
394 {
395     auto *thread = ManagedThread::GetCurrent();
396     auto ctx = GetLanguageContext(thread);
397 
398     ThrowException(ctx, thread, ctx.GetInstantiationErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
399 }
400 
ThrowNoClassDefFoundError(const PandaString & msg)401 void ThrowNoClassDefFoundError(const PandaString &msg)
402 {
403     auto *thread = ManagedThread::GetCurrent();
404     auto ctx = GetLanguageContext(thread);
405 
406     ThrowException(ctx, thread, ctx.GetNoClassDefFoundErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
407 }
408 
ThrowTypedErrorDyn(const std::string & msg)409 void ThrowTypedErrorDyn(const std::string &msg)
410 {
411     auto *thread = ManagedThread::GetCurrent();
412     auto ctx = GetLanguageContext(thread);
413     ThrowException(ctx, thread, ctx.GetTypedErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
414 }
415 
ThrowReferenceErrorDyn(const std::string & msg)416 void ThrowReferenceErrorDyn(const std::string &msg)
417 {
418     auto *thread = ManagedThread::GetCurrent();
419     auto ctx = GetLanguageContext(thread);
420     ThrowException(ctx, thread, ctx.GetReferenceErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
421 }
422 
ThrowIllegalMonitorStateException(const PandaString & msg)423 void ThrowIllegalMonitorStateException(const PandaString &msg)
424 {
425     auto *thread = ManagedThread::GetCurrent();
426     auto ctx = GetLanguageContext(thread);
427 
428     ThrowException(ctx, thread, ctx.GetIllegalMonitorStateExceptionDescriptor(), utf::CStringAsMutf8(msg.c_str()));
429 }
430 
ThrowCloneNotSupportedException()431 void ThrowCloneNotSupportedException()
432 {
433     auto *thread = ManagedThread::GetCurrent();
434     auto ctx = GetLanguageContext(thread);
435     PandaString msg = "Class doesn't implement Cloneable";
436     ThrowException(ctx, thread, ctx.GetCloneNotSupportedExceptionDescriptor(), utf::CStringAsMutf8(msg.c_str()));
437 }
438 
439 }  // namespace panda
440