• 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 * mutf8Name,const uint8_t * mutf8Msg)38 void ThrowException(const LanguageContext &ctx, ManagedThread *thread, const uint8_t *mutf8Name,
39                     const uint8_t *mutf8Msg)
40 {
41     ctx.ThrowException(thread, mutf8Name, mutf8Msg);
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     SetExceptionEvent(events::ExceptionType::NULL_CHECK, thread);
61 }
62 
ThrowStackOverflowException(ManagedThread * thread)63 void ThrowStackOverflowException(ManagedThread *thread)
64 {
65     auto ctx = GetLanguageContext(thread);
66     ctx.ThrowStackOverflowException(thread);
67 }
68 
ThrowArrayIndexOutOfBoundsException(coretypes::ArraySsizeT idx,coretypes::ArraySizeT length)69 void ThrowArrayIndexOutOfBoundsException(coretypes::ArraySsizeT idx, coretypes::ArraySizeT length)
70 {
71     auto *thread = ManagedThread::GetCurrent();
72     auto ctx = GetLanguageContext(thread);
73     ThrowArrayIndexOutOfBoundsException(idx, length, ctx, thread);
74 }
75 
ThrowArrayIndexOutOfBoundsException(coretypes::ArraySsizeT idx,coretypes::ArraySizeT length,const LanguageContext & ctx,ManagedThread * thread)76 void ThrowArrayIndexOutOfBoundsException(coretypes::ArraySsizeT idx, coretypes::ArraySizeT length,
77                                          const LanguageContext &ctx, ManagedThread *thread)
78 {
79     PandaString msg = "idx = " + ToPandaString(idx) + "; length = " + ToPandaString(length);
80 
81     ThrowException(ctx, thread, ctx.GetArrayIndexOutOfBoundsExceptionClassDescriptor(),
82                    utf::CStringAsMutf8(msg.c_str()));
83     SetExceptionEvent(events::ExceptionType::BOUND_CHECK, thread);
84 }
85 
ThrowIndexOutOfBoundsException(coretypes::ArraySsizeT idx,coretypes::ArraySsizeT length)86 void ThrowIndexOutOfBoundsException(coretypes::ArraySsizeT idx, coretypes::ArraySsizeT length)
87 {
88     auto *thread = ManagedThread::GetCurrent();
89     auto ctx = GetLanguageContext(thread);
90 
91     PandaString 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::ArraySsizeT idx,coretypes::ArraySizeT length)103 void ThrowStringIndexOutOfBoundsException(coretypes::ArraySsizeT idx, coretypes::ArraySizeT length)
104 {
105     auto *thread = ManagedThread::GetCurrent();
106     auto ctx = GetLanguageContext(thread);
107 
108     PandaString msg = "idx = " + ToPandaString(idx) + "; length = " + ToPandaString(length);
109 
110     ThrowException(ctx, thread, ctx.GetStringIndexOutOfBoundsExceptionClassDescriptor(),
111                    utf::CStringAsMutf8(msg.c_str()));
112     SetExceptionEvent(events::ExceptionType::BOUND_CHECK, thread);
113 }
114 
ThrowNegativeArraySizeException(coretypes::ArraySsizeT size)115 void ThrowNegativeArraySizeException(coretypes::ArraySsizeT size)
116 {
117     auto *thread = ManagedThread::GetCurrent();
118     auto ctx = GetLanguageContext(thread);
119 
120     PandaString msg = "size = " + ToPandaString(size);
121 
122     ThrowException(ctx, thread, ctx.GetNegativeArraySizeExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
123 }
124 
ThrowNegativeArraySizeException(const PandaString & msg)125 void ThrowNegativeArraySizeException(const PandaString &msg)
126 {
127     auto *thread = ManagedThread::GetCurrent();
128     auto ctx = GetLanguageContext(thread);
129     ThrowException(ctx, thread, ctx.GetNegativeArraySizeExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
130     SetExceptionEvent(events::ExceptionType::NEGATIVE_SIZE, thread);
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     SetExceptionEvent(events::ExceptionType::ARITHMETIC, thread);
139 }
140 
ThrowClassCastException(const Class * dstType,const Class * srcType)141 void ThrowClassCastException(const Class *dstType, const Class *srcType)
142 {
143     auto *thread = ManagedThread::GetCurrent();
144     auto ctx = GetLanguageContext(thread);
145 
146     PandaString msg = ConvertToString(srcType->GetName() + " cannot be cast to " + dstType->GetName());
147 
148     ThrowException(ctx, thread, ctx.GetClassCastExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
149     SetExceptionEvent(events::ExceptionType::CAST_CHECK, thread);
150 }
151 
ThrowAbstractMethodError(const Method * method)152 void ThrowAbstractMethodError(const Method *method)
153 {
154     auto *thread = ManagedThread::GetCurrent();
155     auto ctx = GetLanguageContext(thread);
156 
157     PandaString msg = ConvertToString("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     SetExceptionEvent(events::ExceptionType::ABSTRACT_METHOD, thread);
163 }
164 
ThrowIncompatibleClassChangeErrorForMethodConflict(const Method * method)165 void ThrowIncompatibleClassChangeErrorForMethodConflict(const Method *method)
166 {
167     auto *thread = ManagedThread::GetCurrent();
168     auto ctx = GetLanguageContext(thread);
169 
170     PandaString msg = "Conflicting default method implementations \"";
171     msg += method->GetClass()->GetName() + ".";
172     msg += utf::Mutf8AsCString(method->GetName().data);
173     msg += "\"";
174 
175     ThrowException(ctx, thread, ctx.GetIncompatibleClassChangeErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
176     SetExceptionEvent(events::ExceptionType::ICCE_METHOD_CONFLICT, thread);
177 }
178 
ThrowArrayStoreException(const Class * arrayClass,const Class * elementClass)179 void ThrowArrayStoreException(const Class *arrayClass, const Class *elementClass)
180 {
181     PandaStringStream ss;
182     ss << elementClass->GetName() << " cannot be stored in an array of type " << arrayClass->GetName();
183     ThrowArrayStoreException(ss.str());
184 }
185 
ThrowArrayStoreException(const PandaString & msg)186 void ThrowArrayStoreException(const PandaString &msg)
187 {
188     auto *thread = ManagedThread::GetCurrent();
189     auto ctx = GetLanguageContext(thread);
190 
191     ThrowException(ctx, thread, ctx.GetArrayStoreExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
192 }
193 
ThrowRuntimeException(const PandaString & msg)194 void ThrowRuntimeException(const PandaString &msg)
195 {
196     auto *thread = ManagedThread::GetCurrent();
197     auto ctx = GetLanguageContext(thread);
198 
199     ThrowException(ctx, thread, ctx.GetRuntimeExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
200 }
201 
ThrowIllegalArgumentException(const PandaString & msg)202 void ThrowIllegalArgumentException(const PandaString &msg)
203 {
204     auto *thread = ManagedThread::GetCurrent();
205     auto ctx = GetLanguageContext(thread);
206 
207     ThrowException(ctx, thread, ctx.GetIllegalArgumentExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
208 }
209 
ThrowClassCircularityError(const PandaString & className,const LanguageContext & ctx)210 void ThrowClassCircularityError(const PandaString &className, const LanguageContext &ctx)
211 {
212     auto *thread = ManagedThread::GetCurrent();
213     PandaString msg = "Class or interface \"" + className + "\" is its own superclass or superinterface";
214     ThrowException(ctx, thread, ctx.GetClassCircularityErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
215 }
216 
217 /**
218  * The function finds the corresponding catch block for the exception in the thread.
219  * The function uses thread as an exception storage because:
220  *  1. thread's exception is a GC root
221  *  2. we cannot use HandleScope here because the function is [[noreturn]]
222  */
223 // NOLINTNEXTLINE(google-runtime-references)
FindCatchBlockInCFrames(ManagedThread * thread,StackWalker * stack,Frame * origFrame)224 NO_ADDRESS_SANITIZE void FindCatchBlockInCFrames(ManagedThread *thread, StackWalker *stack, Frame *origFrame)
225 {
226     auto nextFrame = stack->GetNextFrame();
227     for (; stack->HasFrame(); stack->NextFrame(), nextFrame = stack->GetNextFrame()) {
228         LOG(DEBUG, INTEROP) << "Search for the catch block in " << stack->GetMethod()->GetFullName();
229 
230         auto pc = stack->GetBytecodePc();
231         auto *method = stack->GetMethod();
232         ASSERT(method != nullptr);
233         uint32_t pcOffset = method->FindCatchBlock(thread->GetException()->ClassAddr<Class>(), pc);
234         if (pcOffset != panda_file::INVALID_OFFSET) {
235             if (origFrame != nullptr) {
236                 FreeFrame(origFrame);
237             }
238 
239             LOG(DEBUG, INTEROP) << "Catch block is found in " << stack->GetMethod()->GetFullName();
240             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
241             Deoptimize(stack, method->GetInstructions() + pcOffset);
242             UNREACHABLE();
243         }
244 
245         thread->GetVM()->HandleReturnFrame();
246 
247         if (!nextFrame.IsCFrame()) {
248             if (origFrame != nullptr) {
249                 FreeFrame(origFrame);
250             }
251             thread->SetCurrentFrame(nextFrame.GetIFrame());
252             LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame isn't CFrame";
253             DropCompiledFrame(stack);
254             UNREACHABLE();
255         }
256 
257         if (nextFrame.GetCFrame().IsNative()) {
258             if (origFrame != nullptr) {
259                 FreeFrame(origFrame);
260             }
261             LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is NATIVE";
262             DropCompiledFrame(stack);
263             UNREACHABLE();
264         }
265 
266         if (method->IsStaticConstructor()) {
267             if (origFrame != nullptr) {
268                 FreeFrame(origFrame);
269             }
270             LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is StaticConstructor";
271             DropCompiledFrame(stack);
272             UNREACHABLE();
273         }
274 
275         if (!stack->IsInlined()) {
276             auto prev = stack->GetCFrame().GetPrevFrame();
277             if (stack->GetBoundaryFrameMethod<FrameKind::COMPILER>(prev) == FrameBridgeKind::BYPASS) {
278                 /**
279                  * There is bypass bridge and current frame is not inlined, hence we are going to exit compiled
280                  * function. Dynamic languages may do c2c call through runtime, so it's necessary to return to exit
281                  * active function properly.
282                  */
283                 if (origFrame != nullptr) {
284                     FreeFrame(origFrame);
285                 }
286                 LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is caller's cframe";
287                 DropCompiledFrame(stack);
288                 UNREACHABLE();
289             }
290         }
291     }
292 
293     if (nextFrame.IsValid()) {
294         LOG(DEBUG, INTEROP) << "Exception " << thread->GetException()->ClassAddr<Class>()->GetName() << " isn't found";
295         EVENT_METHOD_EXIT(stack->GetMethod()->GetFullName(), events::MethodExitKind::COMPILED,
296                           thread->RecordMethodExit());
297         thread->GetVM()->HandleReturnFrame();
298         DropCompiledFrame(stack);
299     }
300     UNREACHABLE();
301 }
302 
303 /**
304  * The function finds the corresponding catch block for the exception in the thread.
305  * The function uses thread as an exception storage because:
306  *  1. thread's exception is a GC root
307  *  2. we cannot use Handl;eScope her ebecause the function is [[noreturn]]
308  */
FindCatchBlockInCallStack(ManagedThread * thread)309 NO_ADDRESS_SANITIZE void FindCatchBlockInCallStack(ManagedThread *thread)
310 {
311     auto stack = StackWalker::Create(thread);
312     auto origFrame = stack.GetIFrame();
313     ASSERT(!stack.IsCFrame());
314     LOG(DEBUG, INTEROP) << "Enter in FindCatchBlockInCallStack for " << origFrame->GetMethod()->GetFullName();
315     // Exception will be handled in the Method::Invoke's caller
316     if (origFrame->IsInvoke()) {
317         return;
318     }
319 
320     stack.NextFrame();
321 
322     // NATIVE frames can handle exceptions as well
323     if (!stack.HasFrame() || !stack.IsCFrame() || stack.GetCFrame().IsNative()) {
324         return;
325     }
326     thread->GetVM()->HandleReturnFrame();
327     FindCatchBlockInCFrames(thread, &stack, origFrame);
328 }
329 
ThrowFileNotFoundException(const PandaString & msg)330 void ThrowFileNotFoundException(const PandaString &msg)
331 {
332     auto *thread = ManagedThread::GetCurrent();
333     auto ctx = GetLanguageContext(thread);
334 
335     ThrowException(ctx, thread, ctx.GetFileNotFoundExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
336 }
337 
ThrowIOException(const PandaString & msg)338 void ThrowIOException(const PandaString &msg)
339 {
340     auto *thread = ManagedThread::GetCurrent();
341     auto ctx = GetLanguageContext(thread);
342 
343     ThrowException(ctx, thread, ctx.GetIOExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
344 }
345 
ThrowIllegalAccessException(const PandaString & msg)346 void ThrowIllegalAccessException(const PandaString &msg)
347 {
348     auto *thread = ManagedThread::GetCurrent();
349     auto ctx = GetLanguageContext(thread);
350 
351     ThrowException(ctx, thread, ctx.GetIllegalAccessExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
352 }
353 
ThrowOutOfMemoryError(ManagedThread * thread,const PandaString & msg)354 void ThrowOutOfMemoryError(ManagedThread *thread, const PandaString &msg)
355 {
356     auto ctx = GetLanguageContext(thread);
357 
358     if (thread->IsThrowingOOM()) {
359         thread->SetUsePreAllocObj(true);
360     }
361 
362     thread->SetThrowingOOM(true);
363     ThrowException(ctx, thread, ctx.GetOutOfMemoryErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
364     thread->SetThrowingOOM(false);
365     SetExceptionEvent(events::ExceptionType::NATIVE, thread);
366 }
367 
ThrowOutOfMemoryError(const PandaString & msg)368 void ThrowOutOfMemoryError(const PandaString &msg)
369 {
370     auto *thread = ManagedThread::GetCurrent();
371     ThrowOutOfMemoryError(thread, msg);
372 }
373 
ThrowUnsupportedOperationException()374 void ThrowUnsupportedOperationException()
375 {
376     auto *thread = ManagedThread::GetCurrent();
377     auto ctx = GetLanguageContext(thread);
378     ThrowException(ctx, thread, ctx.GetUnsupportedOperationExceptionClassDescriptor(), nullptr);
379 }
380 
ThrowVerificationException(const PandaString & msg)381 void ThrowVerificationException(const PandaString &msg)
382 {
383     auto *thread = ManagedThread::GetCurrent();
384     auto ctx = GetLanguageContext(thread);
385 
386     ThrowException(ctx, thread, ctx.GetVerifyErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
387 }
388 
ThrowVerificationException(const LanguageContext & ctx,const PandaString & msg)389 void ThrowVerificationException(const LanguageContext &ctx, const PandaString &msg)
390 {
391     auto *thread = ManagedThread::GetCurrent();
392 
393     ThrowException(ctx, thread, ctx.GetVerifyErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
394 }
395 
ThrowInstantiationError(const PandaString & msg)396 void ThrowInstantiationError(const PandaString &msg)
397 {
398     auto *thread = ManagedThread::GetCurrent();
399     auto ctx = GetLanguageContext(thread);
400 
401     ThrowException(ctx, thread, ctx.GetInstantiationErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
402     SetExceptionEvent(events::ExceptionType::INSTANTIATION_ERROR, thread);
403 }
404 
ThrowNoClassDefFoundError(const PandaString & msg)405 void ThrowNoClassDefFoundError(const PandaString &msg)
406 {
407     auto *thread = ManagedThread::GetCurrent();
408     auto ctx = GetLanguageContext(thread);
409 
410     ThrowException(ctx, thread, ctx.GetNoClassDefFoundErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
411 }
412 
ThrowTypedErrorDyn(const std::string & msg)413 void ThrowTypedErrorDyn(const std::string &msg)
414 {
415     auto *thread = ManagedThread::GetCurrent();
416     auto ctx = GetLanguageContext(thread);
417     ThrowException(ctx, thread, ctx.GetTypedErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
418 }
419 
ThrowReferenceErrorDyn(const std::string & msg)420 void ThrowReferenceErrorDyn(const std::string &msg)
421 {
422     auto *thread = ManagedThread::GetCurrent();
423     auto ctx = GetLanguageContext(thread);
424     ThrowException(ctx, thread, ctx.GetReferenceErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
425 }
426 
ThrowIllegalMonitorStateException(const PandaString & msg)427 void ThrowIllegalMonitorStateException(const PandaString &msg)
428 {
429     auto *thread = ManagedThread::GetCurrent();
430     auto ctx = GetLanguageContext(thread);
431 
432     ThrowException(ctx, thread, ctx.GetIllegalMonitorStateExceptionDescriptor(), utf::CStringAsMutf8(msg.c_str()));
433 }
434 
ThrowCloneNotSupportedException()435 void ThrowCloneNotSupportedException()
436 {
437     auto *thread = ManagedThread::GetCurrent();
438     auto ctx = GetLanguageContext(thread);
439     PandaString msg = "Class doesn't implement Cloneable";
440     ThrowException(ctx, thread, ctx.GetCloneNotSupportedExceptionDescriptor(), utf::CStringAsMutf8(msg.c_str()));
441 }
442 
HandlePendingException(UnwindPolicy policy)443 void HandlePendingException(UnwindPolicy policy)
444 {
445     auto *thread = ManagedThread::GetCurrent();
446     ASSERT(thread->HasPendingException());
447     LOG(DEBUG, INTEROP) << "HandlePendingException";
448 
449     thread->GetVM()->ClearInteropHandleScopes(thread->GetCurrentFrame());
450 
451     auto stack = StackWalker::Create(thread, policy);
452     ASSERT(stack.IsCFrame());
453 
454     FindCatchBlockInCFrames(thread, &stack, nullptr);
455 }
456 
457 }  // namespace panda
458