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