this repo has no description
at trunk 804 lines 30 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "exception-builtins.h" 3 4#include <unistd.h> 5 6#include <cerrno> 7#include <cinttypes> 8 9#include "builtins-module.h" 10#include "builtins.h" 11#include "frame.h" 12#include "module-builtins.h" 13#include "object-builtins.h" 14#include "objects.h" 15#include "runtime.h" 16#include "set-builtins.h" 17#include "sys-module.h" 18#include "traceback-builtins.h" 19#include "tuple-builtins.h" 20#include "type-builtins.h" 21 22namespace py { 23 24static const BuiltinAttribute kBaseExceptionAttributes[] = { 25 {ID(args), RawBaseException::kArgsOffset}, 26 {ID(_base_exception__traceback), RawBaseException::kTracebackOffset, 27 AttributeFlags::kHidden}, 28 {ID(_base_exception__cause), RawBaseException::kCauseOffset, 29 AttributeFlags::kHidden}, 30 {ID(_base_exception__context), RawBaseException::kContextOffset, 31 AttributeFlags::kHidden}, 32 {ID(__suppress_context__), RawBaseException::kSuppressContextOffset}, 33}; 34 35static const BuiltinAttribute kImportErrorAttributes[] = { 36 {ID(msg), RawImportError::kMsgOffset}, 37 {ID(name), RawImportError::kNameOffset}, 38 {ID(path), RawImportError::kPathOffset}, 39}; 40 41static const BuiltinAttribute kStopIterationAttributes[] = { 42 {ID(value), RawStopIteration::kValueOffset}, 43}; 44 45static const BuiltinAttribute kSyntaxErrorAttributes[] = { 46 {ID(filename), RawSyntaxError::kFilenameOffset}, 47 {ID(lineno), RawSyntaxError::kLinenoOffset}, 48 {ID(msg), RawSyntaxError::kMsgOffset}, 49 {ID(offset), RawSyntaxError::kOffsetOffset}, 50 {ID(print_file_and_line), RawSyntaxError::kPrintFileAndLineOffset}, 51 {ID(text), RawSyntaxError::kTextOffset}, 52}; 53 54static const BuiltinAttribute kSystemExitAttributes[] = { 55 {ID(code), RawSystemExit::kCodeOffset}, 56}; 57 58static const BuiltinAttribute kUnicodeErrorBaseAttributes[] = { 59 {ID(encoding), RawUnicodeErrorBase::kEncodingOffset}, 60 {ID(object), RawUnicodeErrorBase::kObjectOffset}, 61 {ID(start), RawUnicodeErrorBase::kStartOffset}, 62 {ID(end), RawUnicodeErrorBase::kEndOffset}, 63 {ID(reason), RawUnicodeErrorBase::kReasonOffset}, 64}; 65 66struct ExceptionTypeSpec { 67 SymbolId name; 68 LayoutId layout_id; 69 LayoutId superclass_id; 70 View<BuiltinAttribute> attributes; 71}; 72 73static const ExceptionTypeSpec kExceptionSpecs[] = { 74 {ID(BaseException), LayoutId::kBaseException, LayoutId::kObject, 75 kBaseExceptionAttributes}, 76 {ID(Exception), LayoutId::kException, LayoutId::kBaseException, 77 kNoAttributes}, 78 {ID(KeyboardInterrupt), LayoutId::kKeyboardInterrupt, 79 LayoutId::kBaseException, kNoAttributes}, 80 {ID(GeneratorExit), LayoutId::kGeneratorExit, LayoutId::kBaseException, 81 kNoAttributes}, 82 {ID(SystemExit), LayoutId::kSystemExit, LayoutId::kBaseException, 83 kSystemExitAttributes}, 84 {ID(ArithmeticError), LayoutId::kArithmeticError, LayoutId::kException, 85 kNoAttributes}, 86 {ID(AssertionError), LayoutId::kAssertionError, LayoutId::kException, 87 kNoAttributes}, 88 {ID(AttributeError), LayoutId::kAttributeError, LayoutId::kException, 89 kNoAttributes}, 90 {ID(BufferError), LayoutId::kBufferError, LayoutId::kException, 91 kNoAttributes}, 92 {ID(EOFError), LayoutId::kEOFError, LayoutId::kException, kNoAttributes}, 93 {ID(ImportError), LayoutId::kImportError, LayoutId::kException, 94 kImportErrorAttributes}, 95 {ID(LookupError), LayoutId::kLookupError, LayoutId::kException, 96 kNoAttributes}, 97 {ID(MemoryError), LayoutId::kMemoryError, LayoutId::kException, 98 kNoAttributes}, 99 {ID(NameError), LayoutId::kNameError, LayoutId::kException, kNoAttributes}, 100 {ID(OSError), LayoutId::kOSError, LayoutId::kException, kNoAttributes}, 101 {ID(ReferenceError), LayoutId::kReferenceError, LayoutId::kException, 102 kNoAttributes}, 103 {ID(RuntimeError), LayoutId::kRuntimeError, LayoutId::kException, 104 kNoAttributes}, 105 {ID(StopIteration), LayoutId::kStopIteration, LayoutId::kException, 106 kStopIterationAttributes}, 107 {ID(StopAsyncIteration), LayoutId::kStopAsyncIteration, 108 LayoutId::kException, kNoAttributes}, 109 {ID(SyntaxError), LayoutId::kSyntaxError, LayoutId::kException, 110 kSyntaxErrorAttributes}, 111 {ID(SystemError), LayoutId::kSystemError, LayoutId::kException, 112 kNoAttributes}, 113 {ID(TypeError), LayoutId::kTypeError, LayoutId::kException, kNoAttributes}, 114 {ID(ValueError), LayoutId::kValueError, LayoutId::kException, 115 kNoAttributes}, 116 {ID(Warning), LayoutId::kWarning, LayoutId::kException, kNoAttributes}, 117 {ID(FloatingPointError), LayoutId::kFloatingPointError, 118 LayoutId::kArithmeticError, kNoAttributes}, 119 {ID(OverflowError), LayoutId::kOverflowError, LayoutId::kArithmeticError, 120 kNoAttributes}, 121 {ID(ZeroDivisionError), LayoutId::kZeroDivisionError, 122 LayoutId::kArithmeticError, kNoAttributes}, 123 {ID(ModuleNotFoundError), LayoutId::kModuleNotFoundError, 124 LayoutId::kImportError, kNoAttributes}, 125 {ID(IndexError), LayoutId::kIndexError, LayoutId::kLookupError, 126 kNoAttributes}, 127 {ID(KeyError), LayoutId::kKeyError, LayoutId::kLookupError, kNoAttributes}, 128 {ID(UnboundLocalError), LayoutId::kUnboundLocalError, LayoutId::kNameError, 129 kNoAttributes}, 130 {ID(BlockingIOError), LayoutId::kBlockingIOError, LayoutId::kOSError, 131 kNoAttributes}, 132 {ID(ChildProcessError), LayoutId::kChildProcessError, LayoutId::kOSError, 133 kNoAttributes}, 134 {ID(ConnectionError), LayoutId::kConnectionError, LayoutId::kOSError, 135 kNoAttributes}, 136 {ID(FileExistsError), LayoutId::kFileExistsError, LayoutId::kOSError, 137 kNoAttributes}, 138 {ID(FileNotFoundError), LayoutId::kFileNotFoundError, LayoutId::kOSError, 139 kNoAttributes}, 140 {ID(InterruptedError), LayoutId::kInterruptedError, LayoutId::kOSError, 141 kNoAttributes}, 142 {ID(IsADirectoryError), LayoutId::kIsADirectoryError, LayoutId::kOSError, 143 kNoAttributes}, 144 {ID(NotADirectoryError), LayoutId::kNotADirectoryError, LayoutId::kOSError, 145 kNoAttributes}, 146 {ID(PermissionError), LayoutId::kPermissionError, LayoutId::kOSError, 147 kNoAttributes}, 148 {ID(ProcessLookupError), LayoutId::kProcessLookupError, LayoutId::kOSError, 149 kNoAttributes}, 150 {ID(TimeoutError), LayoutId::kTimeoutError, LayoutId::kOSError, 151 kNoAttributes}, 152 {ID(BrokenPipeError), LayoutId::kBrokenPipeError, 153 LayoutId::kConnectionError, kNoAttributes}, 154 {ID(ConnectionAbortedError), LayoutId::kConnectionAbortedError, 155 LayoutId::kConnectionError, kNoAttributes}, 156 {ID(ConnectionRefusedError), LayoutId::kConnectionRefusedError, 157 LayoutId::kConnectionError, kNoAttributes}, 158 {ID(ConnectionResetError), LayoutId::kConnectionResetError, 159 LayoutId::kConnectionError, kNoAttributes}, 160 {ID(NotImplementedError), LayoutId::kNotImplementedError, 161 LayoutId::kRuntimeError, kNoAttributes}, 162 {ID(RecursionError), LayoutId::kRecursionError, LayoutId::kRuntimeError, 163 kNoAttributes}, 164 {ID(IndentationError), LayoutId::kIndentationError, LayoutId::kSyntaxError, 165 kNoAttributes}, 166 {ID(TabError), LayoutId::kTabError, LayoutId::kIndentationError, 167 kNoAttributes}, 168 {ID(UserWarning), LayoutId::kUserWarning, LayoutId::kWarning, 169 kNoAttributes}, 170 {ID(DeprecationWarning), LayoutId::kDeprecationWarning, LayoutId::kWarning, 171 kNoAttributes}, 172 {ID(PendingDeprecationWarning), LayoutId::kPendingDeprecationWarning, 173 LayoutId::kWarning, kNoAttributes}, 174 {ID(SyntaxWarning), LayoutId::kSyntaxWarning, LayoutId::kWarning, 175 kNoAttributes}, 176 {ID(RuntimeWarning), LayoutId::kRuntimeWarning, LayoutId::kWarning, 177 kNoAttributes}, 178 {ID(FutureWarning), LayoutId::kFutureWarning, LayoutId::kWarning, 179 kNoAttributes}, 180 {ID(ImportWarning), LayoutId::kImportWarning, LayoutId::kWarning, 181 kNoAttributes}, 182 {ID(UnicodeWarning), LayoutId::kUnicodeWarning, LayoutId::kWarning, 183 kNoAttributes}, 184 {ID(BytesWarning), LayoutId::kBytesWarning, LayoutId::kWarning, 185 kNoAttributes}, 186 {ID(ResourceWarning), LayoutId::kResourceWarning, LayoutId::kWarning, 187 kNoAttributes}, 188 {ID(UnicodeError), LayoutId::kUnicodeError, LayoutId::kValueError, 189 kNoAttributes}, 190 {ID(UnicodeDecodeError), LayoutId::kUnicodeDecodeError, 191 LayoutId::kUnicodeError, kUnicodeErrorBaseAttributes}, 192 {ID(UnicodeEncodeError), LayoutId::kUnicodeEncodeError, 193 LayoutId::kUnicodeError, kUnicodeErrorBaseAttributes}, 194 {ID(UnicodeTranslateError), LayoutId::kUnicodeTranslateError, 195 LayoutId::kUnicodeError, kUnicodeErrorBaseAttributes}, 196}; 197 198LayoutId errorLayoutFromErrno(int errno_value) { 199 switch (errno_value) { 200 case EACCES: 201 return LayoutId::kPermissionError; 202 case EAGAIN: // duplicates EWOULDBLOCK 203 return LayoutId::kBlockingIOError; 204 case EALREADY: 205 return LayoutId::kBlockingIOError; 206 case EINPROGRESS: 207 return LayoutId::kBlockingIOError; 208 case ECHILD: 209 return LayoutId::kChildProcessError; 210 case ECONNABORTED: 211 return LayoutId::kConnectionAbortedError; 212 case ECONNREFUSED: 213 return LayoutId::kConnectionRefusedError; 214 case ECONNRESET: 215 return LayoutId::kConnectionResetError; 216 case EEXIST: 217 return LayoutId::kFileExistsError; 218 case ENOENT: 219 return LayoutId::kFileNotFoundError; 220 case EINTR: 221 return LayoutId::kInterruptedError; 222 case EISDIR: 223 return LayoutId::kIsADirectoryError; 224 case ENOTDIR: 225 return LayoutId::kNotADirectoryError; 226 case EPERM: 227 return LayoutId::kPermissionError; 228 case EPIPE: 229 return LayoutId::kBrokenPipeError; 230 case ESRCH: 231 return LayoutId::kProcessLookupError; 232 case ETIMEDOUT: 233 return LayoutId::kTimeoutError; 234 default: 235 return LayoutId::kOSError; 236 } 237} 238 239bool givenExceptionMatches(Thread* thread, const Object& given, 240 const Object& exc) { 241 HandleScope scope(thread); 242 if (exc.isTuple()) { 243 Tuple tuple(&scope, *exc); 244 Object item(&scope, NoneType::object()); 245 for (word i = 0; i < tuple.length(); i++) { 246 item = tuple.at(i); 247 if (givenExceptionMatches(thread, given, item)) { 248 return true; 249 } 250 } 251 return false; 252 } 253 Runtime* runtime = thread->runtime(); 254 Object given_type(&scope, *given); 255 if (runtime->isInstanceOfBaseException(*given_type)) { 256 given_type = runtime->typeOf(*given); 257 } 258 if (runtime->isInstanceOfType(*given_type) && 259 runtime->isInstanceOfType(*exc)) { 260 Type subtype(&scope, *given_type); 261 Type supertype(&scope, *exc); 262 if (subtype.isBaseExceptionSubclass() && 263 supertype.isBaseExceptionSubclass()) { 264 return typeIsSubclass(*subtype, *supertype); 265 } 266 } 267 return *given_type == *exc; 268} 269 270RawObject createException(Thread* thread, const Type& type, 271 const Object& value) { 272 if (value.isNoneType()) { 273 return Interpreter::call0(thread, type); 274 } 275 if (thread->runtime()->isInstanceOfTuple(*value)) { 276 HandleScope scope(thread); 277 thread->stackPush(*type); 278 Tuple args(&scope, tupleUnderlying(*value)); 279 word length = args.length(); 280 for (word i = 0; i < length; i++) { 281 thread->stackPush(args.at(i)); 282 } 283 return Interpreter::call(thread, /*nargs=*/length); 284 } 285 return Interpreter::call1(thread, type, value); 286} 287 288void normalizeException(Thread* thread, Object* exc, Object* val, 289 Object* traceback) { 290 Runtime* runtime = thread->runtime(); 291 HandleScope scope(thread); 292 293 auto normalize = [&] { 294 if (!runtime->isInstanceOfType(**exc)) return true; 295 Type type(&scope, **exc); 296 if (!type.isBaseExceptionSubclass()) return true; 297 Object value(&scope, **val); 298 Type value_type(&scope, runtime->typeOf(*value)); 299 300 // TODO(bsimmers): Extend this to support all the weird cases allowed by 301 // PyObject_IsSubclass. 302 if (!typeIsSubclass(*value_type, *type)) { 303 // value isn't an instance of type. Replace it with type(value). 304 value = createException(thread, type, value); 305 if (value.isError()) return false; 306 *val = *value; 307 } else if (*value_type != *type) { 308 // value_type is more specific than type, so use it instead. 309 *exc = *value_type; 310 } 311 312 return true; 313 }; 314 315 // If a new exception is raised during normalization, attempt to normalize 316 // that exception. If this process repeats too many times, give up and throw a 317 // RecursionError. If even that exception fails to normalize, abort. 318 const int normalize_limit = 32; 319 for (word i = 0; i <= normalize_limit; i++) { 320 if (normalize()) return; 321 322 if (i == normalize_limit - 1) { 323 thread->raiseWithFmt( 324 LayoutId::kRecursionError, 325 "maximum recursion depth exceeded while normalizing an exception"); 326 } 327 328 *exc = thread->pendingExceptionType(); 329 *val = thread->pendingExceptionValue(); 330 Object new_tb(&scope, thread->pendingExceptionTraceback()); 331 if (!new_tb.isNoneType()) *traceback = *new_tb; 332 thread->clearPendingException(); 333 } 334 335 if (runtime->isInstanceOfType(**exc)) { 336 Type type(&scope, **exc); 337 if (type.builtinBase() == LayoutId::kMemoryError) { 338 UNIMPLEMENTED( 339 "Cannot recover from MemoryErrors while normalizing exceptions."); 340 } 341 UNIMPLEMENTED( 342 "Cannot recover from the recursive normalization of an exception."); 343 } 344} 345 346static void printPendingExceptionImpl(Thread* thread, bool set_sys_last_vars) { 347 HandleScope scope(thread); 348 Runtime* runtime = thread->runtime(); 349 Object type(&scope, thread->pendingExceptionType()); 350 Object system_exit(&scope, runtime->typeAt(LayoutId::kSystemExit)); 351 if (givenExceptionMatches(thread, type, system_exit)) { 352 handleSystemExit(thread); 353 } 354 355 Object value(&scope, thread->pendingExceptionValue()); 356 Object tb(&scope, thread->pendingExceptionTraceback()); 357 thread->clearPendingException(); 358 if (type.isNoneType()) return; 359 360 normalizeException(thread, &type, &value, &tb); 361 BaseException exc(&scope, *value); 362 exc.setTraceback(*tb); 363 364 if (set_sys_last_vars) { 365 Module sys(&scope, runtime->findModuleById(ID(sys))); 366 moduleAtPutById(thread, sys, ID(last_type), type); 367 moduleAtPutById(thread, sys, ID(last_value), value); 368 moduleAtPutById(thread, sys, ID(last_traceback), tb); 369 } 370 371 Object hook(&scope, 372 runtime->lookupNameInModule(thread, ID(sys), ID(excepthook))); 373 if (hook.isError()) { 374 writeStderr(thread, "sys.excepthook is missing\n"); 375 if (displayException(thread, value, tb).isError()) { 376 thread->clearPendingException(); 377 } 378 return; 379 } 380 381 Object result(&scope, Interpreter::call3(thread, hook, type, value, tb)); 382 if (!result.isError()) return; 383 Object type2(&scope, thread->pendingExceptionType()); 384 if (givenExceptionMatches(thread, type2, system_exit)) { 385 handleSystemExit(thread); 386 } 387 Object value2(&scope, thread->pendingExceptionValue()); 388 Object tb2(&scope, thread->pendingExceptionTraceback()); 389 thread->clearPendingException(); 390 normalizeException(thread, &type2, &value2, &tb2); 391 writeStderr(thread, "Error in sys.excepthook:\n"); 392 if (displayException(thread, value2, tb2).isError()) { 393 thread->clearPendingException(); 394 } 395 writeStderr(thread, "\nOriginal exception was:\n"); 396 if (displayException(thread, value, tb).isError()) { 397 thread->clearPendingException(); 398 } 399} 400 401void printPendingException(Thread* thread) { 402 printPendingExceptionImpl(thread, false); 403} 404 405void printPendingExceptionWithSysLastVars(Thread* thread) { 406 printPendingExceptionImpl(thread, true); 407} 408 409// If value has all the attributes of a well-formed SyntaxError, return true and 410// populate all of the given parameters. In that case, filename will be a str 411// and text will be None or a str. Otherwise, return false and the contents of 412// all out parameters are unspecified. 413static bool parseSyntaxError(Thread* thread, const Object& value, 414 Object* message, Object* filename, word* lineno, 415 word* offset, Object* text) { 416 auto fail = [thread] { 417 thread->clearPendingException(); 418 return false; 419 }; 420 421 HandleScope scope(thread); 422 Runtime* runtime = thread->runtime(); 423 Object result(&scope, runtime->attributeAtById(thread, value, ID(msg))); 424 if (result.isError()) return fail(); 425 *message = *result; 426 427 result = runtime->attributeAtById(thread, value, ID(filename)); 428 if (result.isError()) return fail(); 429 if (result.isNoneType()) { 430 *filename = runtime->newStrFromCStr("<string>"); 431 } else if (runtime->isInstanceOfStr(*result)) { 432 *filename = *result; 433 } else { 434 return false; 435 } 436 437 result = runtime->attributeAtById(thread, value, ID(lineno)); 438 if (result.isError()) return fail(); 439 if (runtime->isInstanceOfInt(*result)) { 440 Int ival(&scope, intUnderlying(*result)); 441 if (ival.numDigits() > 1) return false; 442 *lineno = ival.asWord(); 443 } else { 444 return false; 445 } 446 447 result = runtime->attributeAtById(thread, value, ID(offset)); 448 if (result.isError()) return fail(); 449 if (result.isNoneType()) { 450 *offset = -1; 451 } else if (runtime->isInstanceOfInt(*result)) { 452 Int ival(&scope, intUnderlying(*result)); 453 if (ival.numDigits() > 1) return false; 454 *offset = ival.asWord(); 455 } else { 456 return false; 457 } 458 459 result = runtime->attributeAtById(thread, value, ID(text)); 460 if (result.isError()) return fail(); 461 if (result.isNoneType() || runtime->isInstanceOfStr(*result)) { 462 *text = *result; 463 } else { 464 return false; 465 } 466 467 return true; 468} 469 470static RawObject fileWriteString(Thread* thread, const Object& file, 471 const char* c_str) { 472 HandleScope scope(thread); 473 Str str(&scope, thread->runtime()->newStrFromCStr(c_str)); 474 return thread->invokeMethod2(file, ID(write), str); 475} 476 477static RawObject fileWriteObjectStr(Thread* thread, const Object& file, 478 const Object& str) { 479 return thread->invokeMethod2(file, ID(write), str); 480} 481 482// Used to wrap an expression that may return an Error that should be forwarded, 483// or a value that should be ignored otherwise. 484// 485// TODO(bsimmers): Most of the functions that use this should be rewritten in 486// Python once we have enough library support to do so, then we can delete the 487// macro. 488#define MAY_RAISE(expr) \ 489 { \ 490 RawObject result = (expr); \ 491 if (result.isError()) return result; \ 492 } 493 494// Print the source code snippet from a SyntaxError, with a ^ indicating the 495// position of the error. 496static RawObject printErrorText(Thread* thread, const Object& file, word offset, 497 const Object& text_obj) { 498 HandleScope scope(thread); 499 Str text_str(&scope, *text_obj); 500 word length = text_str.length(); 501 // This is gross, but it greatly simplifies the string scanning done by the 502 // rest of the function, and makes maintaining compatibility with CPython 503 // easier. 504 unique_c_ptr<char[]> text_owner(text_str.toCStr()); 505 const char* text = text_owner.get(); 506 507 // Adjust text and offset to not print any lines before the one that has the 508 // cursor. 509 if (offset >= 0) { 510 if (offset > 0 && offset == length && text[offset - 1] == '\n') { 511 offset--; 512 } 513 for (;;) { 514 const char* newline = std::strchr(text, '\n'); 515 if (newline == nullptr || newline - text >= offset) break; 516 word adjust = newline + 1 - text; 517 offset -= adjust; 518 length -= adjust; 519 text += adjust; 520 } 521 while (*text == ' ' || *text == '\t' || *text == '\f') { 522 text++; 523 offset--; 524 } 525 } 526 527 MAY_RAISE(fileWriteString(thread, file, " ")); 528 MAY_RAISE(fileWriteString(thread, file, text)); 529 if (*text == '\0' || text[length - 1] != '\n') { 530 MAY_RAISE(fileWriteString(thread, file, "\n")); 531 } 532 if (offset == -1) return NoneType::object(); 533 MAY_RAISE(fileWriteString(thread, file, " ")); 534 while (--offset > 0) MAY_RAISE(fileWriteString(thread, file, " ")); 535 MAY_RAISE(fileWriteString(thread, file, "^\n")); 536 return NoneType::object(); 537} 538 539// Print the traceback, type, and message of a single exception. 540static RawObject printSingleException(Thread* thread, const Object& file, 541 const Object& value_in) { 542 HandleScope scope(thread); 543 Runtime* runtime = thread->runtime(); 544 Object value(&scope, *value_in); 545 Type type(&scope, runtime->typeOf(*value)); 546 Str type_name(&scope, type.name()); 547 548 if (!runtime->isInstanceOfBaseException(*value)) { 549 MAY_RAISE(fileWriteString( 550 thread, file, 551 "TypeError: print_exception(): Exception expected for value, ")); 552 553 MAY_RAISE(fileWriteObjectStr(thread, file, type_name)); 554 MAY_RAISE(fileWriteString(thread, file, " found\n")); 555 return NoneType::object(); 556 } 557 558 BaseException exc(&scope, *value); 559 Object tb_obj(&scope, exc.traceback()); 560 if (tb_obj.isTraceback()) { 561 Traceback traceback(&scope, *tb_obj); 562 MAY_RAISE(tracebackWrite(thread, traceback, file)); 563 } 564 565 if (runtime->attributeAtById(thread, value, ID(print_file_and_line)) 566 .isError()) { 567 // Ignore the AttributeError or whatever else went wrong during lookup. 568 thread->clearPendingException(); 569 } else { 570 Object message(&scope, NoneType::object()); 571 Object filename(&scope, NoneType::object()); 572 Object text(&scope, NoneType::object()); 573 word lineno, offset; 574 if (parseSyntaxError(thread, value, &message, &filename, &lineno, &offset, 575 &text)) { 576 value = *message; 577 Str filename_str(&scope, *filename); 578 unique_c_ptr<char[]> filename_c_str(filename_str.toCStr()); 579 Str line(&scope, runtime->newStrFromFmt(" File \"%s\", line %w\n", 580 filename_c_str.get(), lineno)); 581 MAY_RAISE(fileWriteObjectStr(thread, file, line)); 582 if (!text.isNoneType()) { 583 MAY_RAISE(printErrorText(thread, file, offset, text)); 584 } 585 } 586 } 587 588 Object module(&scope, runtime->attributeAtById(thread, type, ID(__module__))); 589 if (module.isError() || !runtime->isInstanceOfStr(*module)) { 590 if (module.isError()) thread->clearPendingException(); 591 MAY_RAISE(fileWriteString(thread, file, "<unknown>")); 592 } else { 593 Str module_str(&scope, *module); 594 if (!module_str.equals(runtime->symbols()->at(ID(builtins)))) { 595 MAY_RAISE(fileWriteObjectStr(thread, file, module_str)); 596 MAY_RAISE(fileWriteString(thread, file, ".")); 597 } 598 } 599 600 MAY_RAISE(fileWriteObjectStr(thread, file, type_name)); 601 Object str_obj(&scope, thread->invokeFunction1(ID(builtins), ID(str), value)); 602 if (str_obj.isError()) { 603 thread->clearPendingException(); 604 MAY_RAISE(fileWriteString(thread, file, ": <exception str() failed>")); 605 } else { 606 Str str(&scope, strUnderlying(*str_obj)); 607 if (str != Str::empty()) { 608 MAY_RAISE(fileWriteString(thread, file, ": ")); 609 MAY_RAISE(fileWriteObjectStr(thread, file, str)); 610 } 611 } 612 613 MAY_RAISE(fileWriteString(thread, file, "\n")); 614 return NoneType::object(); 615} 616 617// Print the given exception and any cause or context exceptions it chains to. 618static RawObject printExceptionChain(Thread* thread, const Object& file, 619 const Object& value, const Set& seen) { 620 Runtime* runtime = thread->runtime(); 621 HandleScope scope(thread); 622 Object hash_obj(&scope, Interpreter::hash(thread, value)); 623 if (hash_obj.isErrorException()) return *hash_obj; 624 word hash = SmallInt::cast(*hash_obj).value(); 625 setAdd(thread, seen, value, hash); 626 627 if (runtime->isInstanceOfBaseException(*value)) { 628 BaseException exc(&scope, *value); 629 Object cause(&scope, exc.cause()); 630 Object context(&scope, exc.context()); 631 if (!cause.isNoneType()) { 632 hash_obj = Interpreter::hash(thread, cause); 633 if (hash_obj.isErrorException()) return *hash_obj; 634 hash = SmallInt::cast(*hash_obj).value(); 635 if (!setIncludes(thread, seen, cause, hash)) { 636 MAY_RAISE(printExceptionChain(thread, file, cause, seen)); 637 MAY_RAISE( 638 fileWriteString(thread, file, 639 "\nThe above exception was the direct cause of the " 640 "following exception:\n\n")); 641 } 642 } else if (!context.isNoneType() && 643 exc.suppressContext() != RawBool::trueObj()) { 644 hash_obj = Interpreter::hash(thread, context); 645 if (hash_obj.isErrorException()) return *hash_obj; 646 hash = SmallInt::cast(*hash_obj).value(); 647 if (!setIncludes(thread, seen, context, hash)) { 648 MAY_RAISE(printExceptionChain(thread, file, context, seen)); 649 MAY_RAISE( 650 fileWriteString(thread, file, 651 "\nDuring handling of the above exception, another " 652 "exception occurred:\n\n")); 653 } 654 } 655 } 656 657 MAY_RAISE(printSingleException(thread, file, value)); 658 return NoneType::object(); 659} 660 661#undef MAY_RAISE 662 663RawObject displayException(Thread* thread, const Object& value, 664 const Object& traceback) { 665 HandleScope scope(thread); 666 Runtime* runtime = thread->runtime(); 667 if (runtime->isInstanceOfBaseException(*value) && traceback.isTraceback()) { 668 BaseException exc(&scope, *value); 669 if (exc.traceback().isNoneType()) exc.setTraceback(*traceback); 670 } 671 672 ValueCell sys_stderr_cell(&scope, runtime->sysStderr()); 673 if (sys_stderr_cell.isUnbound()) { 674 fputs("lost sys.stderr\n", stderr); 675 return NoneType::object(); 676 } 677 Object sys_stderr(&scope, sys_stderr_cell.value()); 678 if (sys_stderr.isNoneType()) { 679 return NoneType::object(); 680 } 681 Set seen(&scope, runtime->newSet()); 682 return printExceptionChain(thread, sys_stderr, value, seen); 683} 684 685void handleSystemExit(Thread* thread) { 686 auto do_exit = [thread](int exit_code) { 687 thread->clearPendingException(); 688 Runtime* runtime = thread->runtime(); 689 delete runtime; 690 std::exit(exit_code); 691 }; 692 693 Runtime* runtime = thread->runtime(); 694 HandleScope scope(thread); 695 Object arg(&scope, thread->pendingExceptionValue()); 696 if (runtime->isInstanceOfSystemExit(*arg)) { 697 // The exception could be raised by either native or managed code. If 698 // native, there will be no SystemExit object. If managed, there will 699 // be one to unpack. 700 SystemExit exc(&scope, *arg); 701 arg = exc.code(); 702 } 703 if (arg.isNoneType()) do_exit(EXIT_SUCCESS); 704 if (runtime->isInstanceOfInt(*arg)) { 705 // We could convert and check for overflow error, but the overflow error 706 // should get cleared anyway. 707 do_exit(intUnderlying(*arg).asWordSaturated()); 708 } 709 710 // The calls below can't have an exception pending 711 thread->clearPendingException(); 712 713 Object result(&scope, thread->invokeMethod1(arg, ID(__str__))); 714 if (!runtime->isInstanceOfStr(*result)) { 715 // The calls below can't have an exception pending 716 thread->clearPendingException(); 717 // No __repr__ method or __repr__ raised. Either way, we can't handle it. 718 result = runtime->newStrFromCStr(""); 719 } 720 721 Str result_str(&scope, *result); 722 ValueCell sys_stderr_cell(&scope, runtime->sysStderr()); 723 if (sys_stderr_cell.isUnbound() || sys_stderr_cell.value().isNoneType()) { 724 unique_c_ptr<char> buf(result_str.toCStr()); 725 fwrite(buf.get(), 1, result_str.length(), stderr); 726 fputc('\n', stderr); 727 } else { 728 Object file(&scope, sys_stderr_cell.value()); 729 fileWriteObjectStr(thread, file, result_str); 730 thread->clearPendingException(); 731 fileWriteString(thread, file, "\n"); 732 } 733 do_exit(EXIT_FAILURE); 734} 735 736RawObject METH(BaseException, __init__)(Thread* thread, Arguments args) { 737 HandleScope scope(thread); 738 Object self_obj(&scope, args.get(0)); 739 if (!thread->runtime()->isInstanceOfBaseException(*self_obj)) { 740 return thread->raiseRequiresType(self_obj, ID(BaseException)); 741 } 742 BaseException self(&scope, *self_obj); 743 Object args_obj(&scope, args.get(1)); 744 self.setArgs(*args_obj); 745 self.setCause(Unbound::object()); 746 self.setContext(Unbound::object()); 747 self.setTraceback(Unbound::object()); 748 self.setSuppressContext(RawBool::falseObj()); 749 return NoneType::object(); 750} 751 752RawObject METH(StopIteration, __init__)(Thread* thread, Arguments args) { 753 HandleScope scope(thread); 754 Object self_obj(&scope, args.get(0)); 755 if (!thread->runtime()->isInstanceOfStopIteration(*self_obj)) { 756 return thread->raiseRequiresType(self_obj, ID(StopIteration)); 757 } 758 StopIteration self(&scope, *self_obj); 759 Object args_obj(&scope, args.get(1)); 760 self.setArgs(*args_obj); 761 self.setCause(Unbound::object()); 762 self.setContext(Unbound::object()); 763 self.setTraceback(Unbound::object()); 764 self.setSuppressContext(RawBool::falseObj()); 765 Tuple tuple(&scope, self.args()); 766 if (tuple.length() > 0) self.setValue(tuple.at(0)); 767 return NoneType::object(); 768} 769 770RawObject METH(SystemExit, __init__)(Thread* thread, Arguments args) { 771 HandleScope scope(thread); 772 Object self_obj(&scope, args.get(0)); 773 if (!thread->runtime()->isInstanceOfSystemExit(*self_obj)) { 774 return thread->raiseRequiresType(self_obj, ID(SystemExit)); 775 } 776 SystemExit self(&scope, *self_obj); 777 RawObject result = METH(BaseException, __init__)(thread, args); 778 if (result.isError()) { 779 return result; 780 } 781 Tuple tuple(&scope, self.args()); 782 if (tuple.length() > 0) { 783 self.setCode(tuple.at(0)); 784 } 785 return NoneType::object(); 786} 787 788void initializeExceptionTypes(Thread* thread) { 789 HandleScope scope(thread); 790 Runtime* runtime = thread->runtime(); 791 Layout layout(&scope, runtime->layoutAt(LayoutId::kNoneType)); 792 Type type(&scope, layout.describedType()); 793 for (ExceptionTypeSpec spec : kExceptionSpecs) { 794 Layout super_layout(&scope, runtime->layoutAt(spec.superclass_id)); 795 word size = (Tuple::cast(super_layout.inObjectAttributes()).length() + 796 spec.attributes.length()) * 797 kPointerSize; 798 type = addBuiltinType(thread, spec.name, spec.layout_id, spec.superclass_id, 799 spec.attributes, size, /*basetype=*/true); 800 builtinTypeEnableTupleOverflow(thread, type); 801 } 802} 803 804} // namespace py