this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <unistd.h>
3
4#include <cerrno>
5#include <cstdarg>
6
7#include "cpython-data.h"
8#include "cpython-func.h"
9
10#include "api-handle.h"
11#include "dict-builtins.h"
12#include "exception-builtins.h"
13#include "fileutils.h"
14#include "runtime.h"
15#include "sys-module.h"
16#include "thread.h"
17#include "traceback-builtins.h"
18#include "type-builtins.h"
19
20namespace py {
21
22PY_EXPORT void PyErr_SetString(PyObject* exc, const char* msg) {
23 PyObject* value = PyUnicode_FromString(msg);
24 PyErr_SetObject(exc, value);
25 Py_XDECREF(value);
26}
27
28PY_EXPORT PyObject* PyErr_Occurred() {
29 Thread* thread = Thread::current();
30 if (!thread->hasPendingException()) {
31 return nullptr;
32 }
33 return ApiHandle::borrowedReference(thread->runtime(),
34 thread->pendingExceptionType());
35}
36
37PY_EXPORT PyObject* PyErr_Format(PyObject* exception, const char* format, ...) {
38 va_list vargs;
39 va_start(vargs, format);
40 PyErr_FormatV(exception, format, vargs);
41 va_end(vargs);
42 return nullptr;
43}
44
45PY_EXPORT void PyErr_Clear() { Thread::current()->clearPendingException(); }
46
47PY_EXPORT int PyErr_BadArgument() {
48 Thread* thread = Thread::current();
49 thread->raiseBadArgument();
50 return 0;
51}
52
53PY_EXPORT PyObject* PyErr_NoMemory() {
54 Thread* thread = Thread::current();
55 thread->raiseMemoryError();
56 return nullptr;
57}
58
59PY_EXPORT PyObject* _PyErr_FormatFromCause(PyObject* exception,
60 const char* format, ...) {
61 CHECK(PyErr_Occurred(),
62 "_PyErr_FormatFromCause must be called with an exception set");
63 PyObject* exc = nullptr;
64 PyObject* val = nullptr;
65 PyObject* tb = nullptr;
66 PyErr_Fetch(&exc, &val, &tb);
67 PyErr_NormalizeException(&exc, &val, &tb);
68 if (tb != nullptr) {
69 PyException_SetTraceback(val, tb);
70 Py_DECREF(tb);
71 }
72 Py_DECREF(exc);
73 DCHECK(!PyErr_Occurred(), "error must not have occurred");
74
75 va_list vargs;
76 va_start(vargs, format);
77 PyErr_FormatV(exception, format, vargs);
78 va_end(vargs);
79
80 PyObject* val2 = nullptr;
81 PyErr_Fetch(&exc, &val2, &tb);
82 PyErr_NormalizeException(&exc, &val2, &tb);
83 Py_INCREF(val);
84 PyException_SetCause(val2, val);
85 PyException_SetContext(val2, val);
86 PyErr_Restore(exc, val2, tb);
87
88 return nullptr;
89}
90
91// Remove the preprocessor macro for PyErr_BadInternalCall() so that we can
92// export the entry point for existing object code:
93#pragma push_macro("PyErr_BadInternalCall")
94#undef PyErr_BadInternalCall
95PY_EXPORT void PyErr_BadInternalCall() {
96 Thread* thread = Thread::current();
97 thread->raiseBadInternalCall();
98}
99#pragma pop_macro("PyErr_BadInternalCall")
100
101PY_EXPORT int PyErr_ExceptionMatches(PyObject* exc) {
102 return PyErr_GivenExceptionMatches(PyErr_Occurred(), exc);
103}
104
105PY_EXPORT void PyErr_Fetch(PyObject** pexc, PyObject** pval, PyObject** ptb) {
106 Thread* thread = Thread::current();
107 Runtime* runtime = thread->runtime();
108 DCHECK(pexc != nullptr, "pexc is null");
109 if (thread->pendingExceptionType().isNoneType()) {
110 *pexc = nullptr;
111 } else {
112 *pexc = ApiHandle::newReference(runtime, thread->pendingExceptionType());
113 }
114 DCHECK(pval != nullptr, "pval is null");
115 if (thread->pendingExceptionValue().isNoneType()) {
116 *pval = nullptr;
117 } else {
118 *pval = ApiHandle::newReference(runtime, thread->pendingExceptionValue());
119 }
120 DCHECK(ptb != nullptr, "ptb is null");
121 if (thread->pendingExceptionTraceback().isNoneType()) {
122 *ptb = nullptr;
123 } else {
124 *ptb =
125 ApiHandle::newReference(runtime, thread->pendingExceptionTraceback());
126 }
127 thread->clearPendingException();
128}
129
130PY_EXPORT PyObject* PyErr_FormatV(PyObject* exception, const char* format,
131 va_list vargs) {
132 PyErr_Clear(); // Cannot call PyUnicode_FromFormatV with an exception set
133
134 PyObject* string = PyUnicode_FromFormatV(format, vargs);
135 PyErr_SetObject(exception, string);
136 Py_XDECREF(string);
137 return nullptr;
138}
139
140PY_EXPORT void PyErr_GetExcInfo(PyObject** p_type, PyObject** p_value,
141 PyObject** p_traceback) {
142 Thread* thread = Thread::current();
143 HandleScope scope(thread);
144 Object caught_exc_state_obj(&scope, thread->topmostCaughtExceptionState());
145 if (caught_exc_state_obj.isNoneType()) {
146 *p_type = nullptr;
147 *p_value = nullptr;
148 *p_traceback = nullptr;
149 return;
150 }
151 Runtime* runtime = thread->runtime();
152 ExceptionState caught_exc_state(&scope, *caught_exc_state_obj);
153 *p_type = ApiHandle::newReference(runtime, caught_exc_state.type());
154 *p_value = ApiHandle::newReference(runtime, caught_exc_state.value());
155 *p_traceback = ApiHandle::newReference(runtime, caught_exc_state.traceback());
156}
157
158PY_EXPORT int PyErr_GivenExceptionMatches(PyObject* given, PyObject* exc) {
159 if (given == nullptr || exc == nullptr) {
160 return 0;
161 }
162 Thread* thread = Thread::current();
163 HandleScope scope(thread);
164 Object given_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(given)));
165 Object exc_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(exc)));
166 return givenExceptionMatches(thread, given_obj, exc_obj) ? 1 : 0;
167}
168
169PY_EXPORT PyObject* PyErr_NewException(const char* name, PyObject* base_or_null,
170 PyObject* dict_or_null) {
171 Thread* thread = Thread::current();
172 const char* dot = std::strrchr(name, '.');
173 if (dot == nullptr) {
174 thread->raiseWithFmt(LayoutId::kSystemError,
175 "PyErr_NewException: name must be module.class");
176 return nullptr;
177 }
178
179 Runtime* runtime = thread->runtime();
180 HandleScope scope(thread);
181 word mod_name_len = dot - name;
182 Object mod_name(&scope,
183 runtime->newStrWithAll(
184 {reinterpret_cast<const byte*>(name), mod_name_len}));
185 Object exc_name(&scope, runtime->newStrFromCStr(dot + 1));
186 Object base(&scope, base_or_null == nullptr
187 ? runtime->typeAt(LayoutId::kException)
188 : ApiHandle::asObject(ApiHandle::fromPyObject(base_or_null)));
189 Object dict(&scope, dict_or_null == nullptr
190 ? runtime->newDict()
191 : ApiHandle::asObject(ApiHandle::fromPyObject(dict_or_null)));
192 Object type(&scope, thread->invokeFunction4(ID(builtins), ID(_exception_new),
193 mod_name, exc_name, base, dict));
194 if (type.isError()) {
195 DCHECK(!type.isErrorNotFound(), "missing _exception_new");
196 return nullptr;
197 }
198 return ApiHandle::newReference(runtime, *type);
199}
200
201PY_EXPORT PyObject* PyErr_NewExceptionWithDoc(const char* name, const char* doc,
202 PyObject* base_or_null,
203 PyObject* dict_or_null) {
204 Thread* thread = Thread::current();
205 HandleScope scope(thread);
206 Runtime* runtime = thread->runtime();
207 Object dict_obj(&scope,
208 dict_or_null == nullptr
209 ? runtime->newDict()
210 : ApiHandle::asObject(ApiHandle::fromPyObject(dict_or_null)));
211 if (doc != nullptr) {
212 if (!runtime->isInstanceOfDict(*dict_obj)) {
213 thread->raiseBadInternalCall();
214 return nullptr;
215 }
216 Dict dict(&scope, *dict_obj);
217 Object doc_str(&scope, runtime->newStrFromCStr(doc));
218 dictAtPutById(thread, dict, ID(__doc__), doc_str);
219 }
220
221 const char* dot = std::strrchr(name, '.');
222 if (dot == nullptr) {
223 thread->raiseWithFmt(LayoutId::kSystemError,
224 "PyErr_NewException: name must be module.class");
225 return nullptr;
226 }
227
228 word mod_name_len = dot - name;
229 Object mod_name(&scope,
230 runtime->newStrWithAll(
231 {reinterpret_cast<const byte*>(name), mod_name_len}));
232 Object exc_name(&scope, runtime->newStrFromCStr(dot + 1));
233 Object base(&scope, base_or_null == nullptr
234 ? runtime->typeAt(LayoutId::kException)
235 : ApiHandle::asObject(ApiHandle::fromPyObject(base_or_null)));
236 Object type(&scope,
237 thread->invokeFunction4(ID(builtins), ID(_exception_new),
238 mod_name, exc_name, base, dict_obj));
239 if (type.isError()) {
240 DCHECK(!type.isErrorNotFound(), "missing _exception_new");
241 return nullptr;
242 }
243 return ApiHandle::newReference(runtime, *type);
244}
245
246PY_EXPORT void PyErr_NormalizeException(PyObject** exc, PyObject** val,
247 PyObject** tb) {
248 Thread* thread = Thread::current();
249 HandleScope scope(thread);
250
251 Object exc_obj(&scope, *exc ? ApiHandle::asObject(ApiHandle::fromPyObject(*exc))
252 : NoneType::object());
253 Object exc_orig(&scope, *exc_obj);
254 Object val_obj(&scope, *val ? ApiHandle::asObject(ApiHandle::fromPyObject(*val))
255 : NoneType::object());
256 Object val_orig(&scope, *val_obj);
257 Object tb_obj(&scope, *tb ? ApiHandle::asObject(ApiHandle::fromPyObject(*tb))
258 : NoneType::object());
259 Object tb_orig(&scope, *tb_obj);
260 normalizeException(thread, &exc_obj, &val_obj, &tb_obj);
261 Runtime* runtime = thread->runtime();
262 if (*exc_obj != *exc_orig) {
263 PyObject* tmp = *exc;
264 *exc = ApiHandle::newReference(runtime, *exc_obj);
265 Py_XDECREF(tmp);
266 }
267 if (*val_obj != *val_orig) {
268 PyObject* tmp = *val;
269 *val = ApiHandle::newReference(runtime, *val_obj);
270 Py_XDECREF(tmp);
271 }
272 if (*tb_obj != *tb_orig) {
273 PyObject* tmp = *tb;
274 *tb = ApiHandle::newReference(runtime, *tb_obj);
275 Py_XDECREF(tmp);
276 }
277}
278
279PY_EXPORT PyObject* PyErr_ProgramText(const char* /* e */, int /* o */) {
280 UNIMPLEMENTED("PyErr_ProgramText");
281}
282
283PY_EXPORT PyObject* PyErr_SetExcFromWindowsErr(PyObject* /* c */, int /* r */) {
284 UNIMPLEMENTED("PyErr_SetExcFromWindowsErr");
285}
286
287PY_EXPORT PyObject* PyErr_SetExcFromWindowsErrWithFilename(
288 PyObject* /* c */, int /* r */, const char* /* e */) {
289 UNIMPLEMENTED("PyErr_SetExcFromWindowsErrWithFilename");
290}
291
292PY_EXPORT PyObject* PyErr_SetExcFromWindowsErrWithFilenameObject(
293 PyObject* /* c */, int /* r */, PyObject* /* t */) {
294 UNIMPLEMENTED("PyErr_SetExcFromWindowsErrWithFilenameObject");
295}
296
297PY_EXPORT PyObject* PyErr_SetExcFromWindowsErrWithFilenameObjects(
298 PyObject* /* c */, int /* r */, PyObject* /* t */, PyObject* /* 2 */) {
299 UNIMPLEMENTED("PyErr_SetExcFromWindowsErrWithFilenameObjects");
300}
301
302PY_EXPORT void PyErr_SetExcInfo(PyObject* type, PyObject* value,
303 PyObject* traceback) {
304 Thread* thread = Thread::current();
305 HandleScope scope(thread);
306 Object type_obj(&scope, type == nullptr ? NoneType::object()
307 : ApiHandle::stealReference(type));
308 thread->setCaughtExceptionType(*type_obj);
309 Object value_obj(&scope, value == nullptr ? NoneType::object()
310 : ApiHandle::stealReference(value));
311 thread->setCaughtExceptionValue(*value_obj);
312 Object traceback_obj(&scope, traceback == nullptr
313 ? NoneType::object()
314 : ApiHandle::stealReference(traceback));
315 thread->setCaughtExceptionTraceback(*traceback_obj);
316}
317
318PY_EXPORT PyObject* PyErr_SetFromErrno(PyObject* type) {
319 int errno_value = errno;
320 Thread* thread = Thread::current();
321 HandleScope scope(thread);
322 Object type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(type)));
323 Object none(&scope, NoneType::object());
324 thread->raiseFromErrnoWithFilenames(type_obj, errno_value, none, none);
325 return nullptr;
326}
327
328PY_EXPORT PyObject* PyErr_SetFromErrnoWithFilename(PyObject* type,
329 const char* filename) {
330 int errno_value = errno;
331 Thread* thread = Thread::current();
332 HandleScope scope(thread);
333 Object type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(type)));
334 Object filename_obj(&scope, thread->runtime()->newStrFromCStr(filename));
335 Object none(&scope, NoneType::object());
336 thread->raiseFromErrnoWithFilenames(type_obj, errno_value, filename_obj,
337 none);
338 return nullptr;
339}
340
341PY_EXPORT PyObject* PyErr_SetFromErrnoWithFilenameObject(PyObject* type,
342 PyObject* filename) {
343 int errno_value = errno;
344 Thread* thread = Thread::current();
345 HandleScope scope(thread);
346 Object type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(type)));
347 Object filename_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(filename)));
348 Object none(&scope, NoneType::object());
349 thread->raiseFromErrnoWithFilenames(type_obj, errno_value, filename_obj,
350 none);
351 return nullptr;
352}
353
354PY_EXPORT PyObject* PyErr_SetFromErrnoWithFilenameObjects(PyObject* type,
355 PyObject* filename0,
356 PyObject* filename1) {
357 int errno_value = errno;
358 Thread* thread = Thread::current();
359 HandleScope scope(thread);
360 Object type_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(type)));
361 Object filename0_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(filename0)));
362 Object filename1_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(filename1)));
363 thread->raiseFromErrnoWithFilenames(type_obj, errno_value, filename0_obj,
364 filename1_obj);
365 return nullptr;
366}
367
368PY_EXPORT PyObject* PyErr_SetFromWindowsErr(int /* r */) {
369 UNIMPLEMENTED("PyErr_SetFromWindowsErr");
370}
371
372PY_EXPORT PyObject* PyErr_SetFromWindowsErrWithFilename(int /* r */,
373 const char* /* e */) {
374 UNIMPLEMENTED("PyErr_SetFromWindowsErrWithFilename");
375}
376
377PY_EXPORT PyObject* PyErr_SetImportError(PyObject* /* g */, PyObject* /* e */,
378 PyObject* /* h */) {
379 UNIMPLEMENTED("PyErr_SetImportError");
380}
381
382PY_EXPORT PyObject* PyErr_SetImportErrorSubclass(PyObject* /* n */,
383 PyObject* /* g */,
384 PyObject* /* e */,
385 PyObject* /* h */) {
386 UNIMPLEMENTED("PyErr_SetImportErrorSubclass");
387}
388
389PY_EXPORT void PyErr_SetNone(PyObject* type) { PyErr_SetObject(type, nullptr); }
390
391PY_EXPORT void PyErr_SetObject(PyObject* exc, PyObject* val) {
392 Thread* thread = Thread::current();
393 if (exc == nullptr) {
394 DCHECK(val == nullptr, "nullptr exc with non-nullptr val");
395 thread->clearPendingException();
396 return;
397 }
398
399 HandleScope scope(thread);
400 Object exc_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(exc)));
401
402 Runtime* runtime = thread->runtime();
403 if (!runtime->isInstanceOfType(*exc_obj) ||
404 !Type(&scope, *exc_obj).isBaseExceptionSubclass()) {
405 Object exc_repr(&scope,
406 thread->invokeFunction1(ID(builtins), ID(repr), exc_obj));
407 if (exc_repr.isErrorException()) return;
408 thread->raiseWithFmt(LayoutId::kSystemError,
409 "exception %S not a BaseException subclass",
410 &exc_repr);
411 return;
412 }
413
414 Type exc_type(&scope, *exc_obj);
415 Object val_obj(&scope, val == nullptr
416 ? NoneType::object()
417 : ApiHandle::asObject(ApiHandle::fromPyObject(val)));
418 val_obj = thread->chainExceptionContext(exc_type, val_obj);
419 if (val_obj.isError()) return;
420 thread->setPendingExceptionType(*exc_obj);
421 thread->setPendingExceptionValue(*val_obj);
422 if (runtime->isInstanceOfBaseException(*val_obj)) {
423 BaseException val_exc(&scope, *val_obj);
424 thread->setPendingExceptionTraceback(val_exc.traceback());
425 }
426}
427
428PY_EXPORT void PyErr_SyntaxLocation(const char* /* e */, int /* o */) {
429 UNIMPLEMENTED("PyErr_SyntaxLocation");
430}
431
432PY_EXPORT void PyErr_SyntaxLocationEx(const char* filename, int lineno,
433 int col_offset) {
434 PyObject* fileobj;
435 if (filename != nullptr) {
436 fileobj = PyUnicode_DecodeFSDefault(filename);
437 if (fileobj == nullptr) {
438 PyErr_Clear();
439 }
440 } else {
441 fileobj = nullptr;
442 }
443 PyErr_SyntaxLocationObject(fileobj, lineno, col_offset);
444 Py_XDECREF(fileobj);
445}
446
447PY_EXPORT void PyErr_SyntaxLocationObject(PyObject* filename, int lineno,
448 int col_offset) {
449 PyObject *exc, *val, *tb;
450 // Add attributes for the line number and filename for the error
451 PyErr_Fetch(&exc, &val, &tb);
452 PyErr_NormalizeException(&exc, &val, &tb);
453 // XXX check that it is, indeed, a syntax error. It might not be, though.
454 PyObject* lineno_obj = PyLong_FromLong(lineno);
455 if (lineno_obj == nullptr) {
456 PyErr_Clear();
457 } else {
458 if (PyObject_SetAttrString(val, "lineno", lineno_obj)) {
459 PyErr_Clear();
460 }
461 Py_DECREF(lineno_obj);
462 }
463 PyObject* col_obj = nullptr;
464 if (col_offset >= 0) {
465 col_obj = PyLong_FromLong(col_offset);
466 if (col_obj == nullptr) {
467 PyErr_Clear();
468 }
469 }
470 if (PyObject_SetAttrString(val, "offset", col_obj ? col_obj : Py_None)) {
471 PyErr_Clear();
472 }
473 Py_XDECREF(col_obj);
474 if (filename != nullptr) {
475 if (PyObject_SetAttrString(val, "filename", filename)) {
476 PyErr_Clear();
477 }
478
479 PyObject* text_obj = PyErr_ProgramTextObject(filename, lineno);
480 if (text_obj) {
481 if (PyObject_SetAttrString(val, "text", text_obj)) {
482 PyErr_Clear();
483 }
484 Py_DECREF(text_obj);
485 }
486 }
487 if (exc != PyExc_SyntaxError) {
488 if (!PyObject_HasAttrString(val, "msg")) {
489 PyObject* msg_obj = PyObject_Str(val);
490 if (msg_obj) {
491 if (PyObject_SetAttrString(val, "msg", msg_obj)) {
492 PyErr_Clear();
493 }
494 Py_DECREF(msg_obj);
495 } else {
496 PyErr_Clear();
497 }
498 }
499 if (!PyObject_HasAttrString(val, "print_file_and_line")) {
500 if (PyObject_SetAttrString(val, "print_file_and_line", Py_None)) {
501 PyErr_Clear();
502 }
503 }
504 }
505 PyErr_Restore(exc, val, tb);
506}
507
508static RawObject fileWriteObjectStrUnraisable(Thread* thread,
509 const Object& file,
510 const Object& obj) {
511 HandleScope scope(thread);
512 Object obj_str(&scope, thread->invokeFunction1(ID(builtins), ID(str), obj));
513 if (obj_str.isError()) {
514 thread->clearPendingException();
515 return *obj_str;
516 }
517 RawObject result = thread->invokeMethod2(file, ID(write), obj_str);
518 thread->clearPendingException();
519 return result;
520}
521
522static RawObject fileWriteObjectReprUnraisable(Thread* thread,
523 const Object& file,
524 const Object& obj) {
525 HandleScope scope(thread);
526 Object obj_repr(&scope, thread->invokeFunction1(ID(builtins), ID(repr), obj));
527 if (obj_repr.isError()) {
528 thread->clearPendingException();
529 return *obj_repr;
530 }
531 RawObject result = thread->invokeMethod2(file, ID(write), obj_repr);
532 thread->clearPendingException();
533 return result;
534}
535
536static RawObject fileWriteCStrUnraisable(Thread* thread, const Object& file,
537 const char* c_str) {
538 HandleScope scope(thread);
539 Object str(&scope, thread->runtime()->newStrFromFmt(c_str));
540 RawObject result = thread->invokeMethod2(file, ID(write), str);
541 thread->clearPendingException();
542 return result;
543}
544
545PY_EXPORT void PyErr_WriteUnraisable(PyObject* obj) {
546 Thread* thread = Thread::current();
547 HandleScope scope(thread);
548 Object exc(&scope, thread->pendingExceptionType());
549 Object val(&scope, thread->pendingExceptionValue());
550 Object tb(&scope, thread->pendingExceptionTraceback());
551 thread->clearPendingException();
552
553 Runtime* runtime = thread->runtime();
554 Object sys_stderr(&scope,
555 runtime->lookupNameInModule(thread, ID(sys), ID(stderr)));
556 if (obj != nullptr) {
557 if (fileWriteCStrUnraisable(thread, sys_stderr, "Exception ignored in: ")
558 .isError()) {
559 return;
560 }
561 Object object(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(obj)));
562 if (fileWriteObjectReprUnraisable(thread, sys_stderr, object).isError()) {
563 if (fileWriteCStrUnraisable(thread, sys_stderr, "<object repr() failed>")
564 .isError()) {
565 return;
566 }
567 }
568 if (fileWriteCStrUnraisable(thread, sys_stderr, "\n").isError()) {
569 return;
570 }
571 }
572
573 if (tb.isTraceback()) {
574 Traceback traceback(&scope, *tb);
575 Object err(&scope, tracebackWrite(thread, traceback, sys_stderr));
576 DCHECK(!err.isErrorException(), "failed to write traceback");
577 }
578
579 if (exc.isNoneType()) {
580 thread->clearPendingException();
581 return;
582 }
583
584 DCHECK(runtime->isInstanceOfType(*exc), "exc must be a type");
585 Type exc_type(&scope, *exc);
586 DCHECK(exc_type.isBaseExceptionSubclass(),
587 "exc must be a subclass of BaseException");
588 // TODO(T42602623): If exc_type.name() is None, Remove dotted components of
589 // name, eg A.B.C => C
590
591 Object module_name_obj(
592 &scope, runtime->attributeAtById(thread, exc_type, ID(__module__)));
593 if (!runtime->isInstanceOfStr(*module_name_obj)) {
594 thread->clearPendingException();
595 if (fileWriteCStrUnraisable(thread, sys_stderr, "<unknown>").isError()) {
596 return;
597 }
598 } else {
599 Str module_name(&scope, *module_name_obj);
600 if (!module_name.equalsCStr("builtins")) {
601 if (fileWriteObjectStrUnraisable(thread, sys_stderr, module_name)
602 .isError()) {
603 return;
604 }
605 if (fileWriteCStrUnraisable(thread, sys_stderr, ".").isError()) {
606 return;
607 }
608 }
609 }
610
611 if (exc_type.name().isNoneType()) {
612 if (fileWriteCStrUnraisable(thread, sys_stderr, "<unknown>").isError()) {
613 return;
614 }
615 } else {
616 Str exc_type_name(&scope, exc_type.name());
617 if (fileWriteObjectStrUnraisable(thread, sys_stderr, exc_type_name)
618 .isError()) {
619 return;
620 }
621 }
622
623 if (!val.isNoneType()) {
624 if (fileWriteCStrUnraisable(thread, sys_stderr, ": ").isError()) {
625 return;
626 }
627 if (fileWriteObjectStrUnraisable(thread, sys_stderr, val).isError()) {
628 if (fileWriteCStrUnraisable(thread, sys_stderr,
629 "<exception str() failed>")
630 .isError()) {
631 return;
632 }
633 }
634 }
635 if (fileWriteCStrUnraisable(thread, sys_stderr, "\n").isError()) {
636 return;
637 }
638}
639
640PY_EXPORT void _PyErr_BadInternalCall(const char* filename, int lineno) {
641 Thread::current()->raiseWithFmt(LayoutId::kSystemError,
642 "%s:%d: bad argument to internal function",
643 filename, lineno);
644}
645
646PY_EXPORT PyObject* PyErr_ProgramTextObject(PyObject* filename, int lineno) {
647 if (filename == nullptr || lineno <= 0) {
648 return nullptr;
649 }
650 Thread* thread = Thread::current();
651 HandleScope scope(thread);
652 Object filename_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(filename)));
653 Object lineno_obj(&scope, SmallInt::fromWord(lineno));
654 Object result(&scope,
655 thread->invokeFunction2(ID(builtins), ID(_err_program_text),
656 filename_obj, lineno_obj));
657 if (result.isErrorException()) {
658 thread->clearPendingException();
659 return nullptr;
660 }
661 if (result == Str::empty()) {
662 return nullptr;
663 }
664 return ApiHandle::newReference(thread->runtime(), *result);
665}
666
667PY_EXPORT void PyErr_Restore(PyObject* type, PyObject* value,
668 PyObject* traceback) {
669 Thread* thread = Thread::current();
670 if (type == nullptr) {
671 thread->setPendingExceptionType(NoneType::object());
672 } else {
673 thread->setPendingExceptionType(ApiHandle::asObject(ApiHandle::fromPyObject(type)));
674 // This is a stolen reference, decrement the reference count
675 ApiHandle::decref(ApiHandle::fromPyObject(type));
676 }
677 if (value == nullptr) {
678 thread->setPendingExceptionValue(NoneType::object());
679 } else {
680 thread->setPendingExceptionValue(
681 ApiHandle::asObject(ApiHandle::fromPyObject(value)));
682 // This is a stolen reference, decrement the reference count
683 ApiHandle::decref(ApiHandle::fromPyObject(value));
684 }
685 if (traceback != nullptr &&
686 !ApiHandle::asObject(ApiHandle::fromPyObject(traceback)).isTraceback()) {
687 ApiHandle::decref(ApiHandle::fromPyObject(traceback));
688 // Can only store traceback instances as the traceback
689 traceback = nullptr;
690 }
691 if (traceback == nullptr) {
692 thread->setPendingExceptionTraceback(NoneType::object());
693 } else {
694 thread->setPendingExceptionTraceback(
695 ApiHandle::asObject(ApiHandle::fromPyObject(traceback)));
696 // This is a stolen reference, decrement the reference count
697 ApiHandle::decref(ApiHandle::fromPyObject(traceback));
698 }
699}
700
701// Like PyErr_Restore(), but if an exception is already set, set the context
702// associated with it.
703PY_EXPORT void _PyErr_ChainExceptions(PyObject* exc, PyObject* val,
704 PyObject* tb) {
705 if (exc == nullptr) return;
706
707 if (PyErr_Occurred()) {
708 PyObject *exc2, *val2, *tb2;
709 PyErr_Fetch(&exc2, &val2, &tb2);
710 PyErr_NormalizeException(&exc, &val, &tb);
711 if (tb != nullptr) {
712 PyException_SetTraceback(val, tb);
713 Py_DECREF(tb);
714 }
715 Py_DECREF(exc);
716 PyErr_NormalizeException(&exc2, &val2, &tb2);
717 PyException_SetContext(val2, val);
718 PyErr_Restore(exc2, val2, tb2);
719 } else {
720 PyErr_Restore(exc, val, tb);
721 }
722}
723
724} // namespace py