1 /**
2 * Copyright (c) 2021-2024 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
DropCFrameIfNecessary(ManagedThread *thread, StackWalker *stack, Frame *origFrame, FrameAccessor nextFrame, Method *method)203 NO_ADDRESS_SANITIZE void DropCFrameIfNecessary(ManagedThread *thread, StackWalker *stack, Frame *origFrame,
204 FrameAccessor nextFrame, Method *method)
205 {
206 if (!nextFrame.IsCFrame()) {
207 if (origFrame != nullptr) {
208 FreeFrame(origFrame);
209 }
210 thread->SetCurrentFrame(nextFrame.GetIFrame());
211 LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame isn't CFrame";
212 DropCompiledFrame(stack);
213 UNREACHABLE();
214 }
215
216 if (nextFrame.GetCFrame().IsNative()) {
217 if (origFrame != nullptr) {
218 FreeFrame(origFrame);
219 }
220 LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is NATIVE";
221 DropCompiledFrame(stack);
222 UNREACHABLE();
223 }
224
225 if (method->IsStaticConstructor()) {
226 if (origFrame != nullptr) {
227 FreeFrame(origFrame);
228 }
229 LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is StaticConstructor";
230 DropCompiledFrame(stack);
231 UNREACHABLE();
232 }
233 }
234
235 /**
236 * The function finds the corresponding catch block for the exception in the thread.
237 * The function uses thread as an exception storage because:
238 * 1. thread's exception is a GC root
239 * 2. we cannot use HandleScope here because the function is [[noreturn]]
240 */
241 // NOLINTNEXTLINE(google-runtime-references)
FindCatchBlockInCFrames(ManagedThread *thread, StackWalker *stack, Frame *origFrame)242 NO_ADDRESS_SANITIZE void FindCatchBlockInCFrames(ManagedThread *thread, StackWalker *stack, Frame *origFrame)
243 {
244 auto nextFrame = stack->GetNextFrame();
245 for (; stack->HasFrame(); stack->NextFrame(), nextFrame = stack->GetNextFrame()) {
246 LOG(DEBUG, INTEROP) << "Search for the catch block in " << stack->GetMethod()->GetFullName();
247
248 auto pc = stack->GetBytecodePc();
249 auto *method = stack->GetMethod();
250 ASSERT(method != nullptr);
251 uint32_t pcOffset = method->FindCatchBlock(thread->GetException()->ClassAddr<Class>(), pc);
252 if (pcOffset != panda_file::INVALID_OFFSET) {
253 if (origFrame != nullptr) {
254 FreeFrame(origFrame);
255 }
256
257 LOG(DEBUG, INTEROP) << "Catch block is found in " << stack->GetMethod()->GetFullName();
258 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
259 Deoptimize(stack, method->GetInstructions() + pcOffset);
260 UNREACHABLE();
261 }
262
263 thread->GetVM()->HandleReturnFrame();
264
265 DropCFrameIfNecessary(thread, stack, origFrame, nextFrame, method);
266
267 if (stack->IsInlined()) {
268 continue;
269 }
270
271 auto prev = stack->GetCFrame().GetPrevFrame();
272 if (stack->GetBoundaryFrameMethod<FrameKind::COMPILER>(prev) == FrameBridgeKind::BYPASS) {
273 /**
274 * There is bypass bridge and current frame is not inlined, hence we are going to exit compiled
275 * function. Dynamic languages may do c2c call through runtime, so it's necessary to return to exit
276 * active function properly.
277 */
278 if (origFrame != nullptr) {
279 FreeFrame(origFrame);
280 }
281 LOG(DEBUG, INTEROP) << "DropCompiledFrameAndReturn. Next frame is caller's cframe";
282 DropCompiledFrame(stack);
283 UNREACHABLE();
284 }
285 }
286
287 if (nextFrame.IsValid()) {
288 LOG(DEBUG, INTEROP) << "Exception " << thread->GetException()->ClassAddr<Class>()->GetName() << " isn't found";
289 EVENT_METHOD_EXIT(stack->GetMethod()->GetFullName(), events::MethodExitKind::COMPILED,
290 thread->RecordMethodExit());
291 thread->GetVM()->HandleReturnFrame();
292 DropCompiledFrame(stack);
293 }
294 UNREACHABLE();
295 }
296
297 /**
298 * The function finds the corresponding catch block for the exception in the thread.
299 * The function uses thread as an exception storage because:
300 * 1. thread's exception is a GC root
301 * 2. we cannot use Handl;eScope her ebecause the function is [[noreturn]]
302 */
FindCatchBlockInCallStack(ManagedThread *thread)303 NO_ADDRESS_SANITIZE void FindCatchBlockInCallStack(ManagedThread *thread)
304 {
305 auto stack = StackWalker::Create(thread);
306 auto origFrame = stack.GetIFrame();
307 ASSERT(!stack.IsCFrame());
308 LOG(DEBUG, INTEROP) << "Enter in FindCatchBlockInCallStack for " << origFrame->GetMethod()->GetFullName();
309 // Exception will be handled in the Method::Invoke's caller
310 if (origFrame->IsInvoke()) {
311 return;
312 }
313
314 stack.NextFrame();
315
316 // NATIVE frames can handle exceptions as well
317 if (!stack.HasFrame() || !stack.IsCFrame() || stack.GetCFrame().IsNative()) {
318 return;
319 }
320 thread->GetVM()->HandleReturnFrame();
321 FindCatchBlockInCFrames(thread, &stack, origFrame);
322 }
323
ThrowFileNotFoundException(const PandaString &msg)324 void ThrowFileNotFoundException(const PandaString &msg)
325 {
326 auto *thread = ManagedThread::GetCurrent();
327 auto ctx = GetLanguageContext(thread);
328
329 ThrowException(ctx, thread, ctx.GetFileNotFoundExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
330 }
331
ThrowIOException(const PandaString &msg)332 void ThrowIOException(const PandaString &msg)
333 {
334 auto *thread = ManagedThread::GetCurrent();
335 auto ctx = GetLanguageContext(thread);
336
337 ThrowException(ctx, thread, ctx.GetIOExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
338 }
339
ThrowIllegalAccessException(const PandaString &msg)340 void ThrowIllegalAccessException(const PandaString &msg)
341 {
342 auto *thread = ManagedThread::GetCurrent();
343 auto ctx = GetLanguageContext(thread);
344
345 ThrowException(ctx, thread, ctx.GetIllegalAccessExceptionClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
346 }
347
ThrowOutOfMemoryError(ManagedThread *thread, const PandaString &msg)348 void ThrowOutOfMemoryError(ManagedThread *thread, const PandaString &msg)
349 {
350 auto ctx = GetLanguageContext(thread);
351
352 if (thread->IsThrowingOOM()) {
353 thread->SetUsePreAllocObj(true);
354 }
355
356 thread->SetThrowingOOM(true);
357 ThrowException(ctx, thread, ctx.GetOutOfMemoryErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
358 thread->SetThrowingOOM(false);
359 SetExceptionEvent(events::ExceptionType::NATIVE, thread);
360 }
361
ThrowOutOfMemoryError(const PandaString &msg)362 void ThrowOutOfMemoryError(const PandaString &msg)
363 {
364 auto *thread = ManagedThread::GetCurrent();
365 ThrowOutOfMemoryError(thread, msg);
366 }
367
ThrowUnsupportedOperationException()368 void ThrowUnsupportedOperationException()
369 {
370 auto *thread = ManagedThread::GetCurrent();
371 auto ctx = GetLanguageContext(thread);
372 ThrowException(ctx, thread, ctx.GetUnsupportedOperationExceptionClassDescriptor(), nullptr);
373 }
374
ThrowVerificationException(const PandaString &msg)375 void ThrowVerificationException(const PandaString &msg)
376 {
377 auto *thread = ManagedThread::GetCurrent();
378 auto ctx = GetLanguageContext(thread);
379
380 ThrowException(ctx, thread, ctx.GetVerifyErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
381 }
382
ThrowVerificationException(const LanguageContext &ctx, const PandaString &msg)383 void ThrowVerificationException(const LanguageContext &ctx, const PandaString &msg)
384 {
385 auto *thread = ManagedThread::GetCurrent();
386
387 ThrowException(ctx, thread, ctx.GetVerifyErrorClassDescriptor(), utf::CStringAsMutf8(msg.c_str()));
388 }
389
ThrowInstantiationError(const PandaString &msg)390 void ThrowInstantiationError(const PandaString &msg)
391 {
392 auto *thread = ManagedThread::GetCurrent();
393 auto ctx = GetLanguageContext(thread);
394
395 ThrowException(ctx, thread, ctx.GetInstantiationErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
396 SetExceptionEvent(events::ExceptionType::INSTANTIATION_ERROR, thread);
397 }
398
ThrowNoClassDefFoundError(const PandaString &msg)399 void ThrowNoClassDefFoundError(const PandaString &msg)
400 {
401 auto *thread = ManagedThread::GetCurrent();
402 auto ctx = GetLanguageContext(thread);
403
404 ThrowException(ctx, thread, ctx.GetNoClassDefFoundErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
405 }
406
ThrowTypedErrorDyn(const std::string &msg)407 void ThrowTypedErrorDyn(const std::string &msg)
408 {
409 auto *thread = ManagedThread::GetCurrent();
410 auto ctx = GetLanguageContext(thread);
411 ThrowException(ctx, thread, ctx.GetTypedErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
412 }
413
ThrowReferenceErrorDyn(const std::string &msg)414 void ThrowReferenceErrorDyn(const std::string &msg)
415 {
416 auto *thread = ManagedThread::GetCurrent();
417 auto ctx = GetLanguageContext(thread);
418 ThrowException(ctx, thread, ctx.GetReferenceErrorDescriptor(), utf::CStringAsMutf8(msg.c_str()));
419 }
420
ThrowIllegalMonitorStateException(const PandaString &msg)421 void ThrowIllegalMonitorStateException(const PandaString &msg)
422 {
423 auto *thread = ManagedThread::GetCurrent();
424 auto ctx = GetLanguageContext(thread);
425
426 ThrowException(ctx, thread, ctx.GetIllegalMonitorStateExceptionDescriptor(), utf::CStringAsMutf8(msg.c_str()));
427 }
428
ThrowCloneNotSupportedException()429 void ThrowCloneNotSupportedException()
430 {
431 auto *thread = ManagedThread::GetCurrent();
432 auto ctx = GetLanguageContext(thread);
433 PandaString msg = "Class doesn't implement Cloneable";
434 ThrowException(ctx, thread, ctx.GetCloneNotSupportedExceptionDescriptor(), utf::CStringAsMutf8(msg.c_str()));
435 }
436
HandlePendingException(UnwindPolicy policy)437 void HandlePendingException(UnwindPolicy policy)
438 {
439 auto *thread = ManagedThread::GetCurrent();
440 ASSERT(thread->HasPendingException());
441 LOG(DEBUG, INTEROP) << "HandlePendingException";
442
443 thread->GetVM()->ClearInteropHandleScopes(thread->GetCurrentFrame());
444
445 auto stack = StackWalker::Create(thread, policy);
446 ASSERT(stack.IsCFrame());
447
448 FindCatchBlockInCFrames(thread, &stack, nullptr);
449 }
450
451 } // namespace ark
452