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