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