@@ -411,175 +411,7 @@ T reinterpret_steal(handle h) {
411
411
}
412
412
413
413
PYBIND11_NAMESPACE_BEGIN (detail)
414
-
415
- // Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class).
416
- inline const char *obj_class_name(PyObject *obj) {
417
- if (Py_TYPE (obj) == &PyType_Type) {
418
- return reinterpret_cast <PyTypeObject *>(obj)->tp_name ;
419
- }
420
- return Py_TYPE (obj)->tp_name ;
421
- }
422
-
423
- std::string error_string ();
424
-
425
- struct error_fetch_and_normalize {
426
- // Immediate normalization is long-established behavior (starting with
427
- // https://github.com/pybind/pybind11/commit/135ba8deafb8bf64a15b24d1513899eb600e2011
428
- // from Sep 2016) and safest. Normalization could be deferred, but this could mask
429
- // errors elsewhere, the performance gain is very minor in typical situations
430
- // (usually the dominant bottleneck is EH unwinding), and the implementation here
431
- // would be more complex.
432
- explicit error_fetch_and_normalize (const char *called) {
433
- PyErr_Fetch (&m_type.ptr (), &m_value.ptr (), &m_trace.ptr ());
434
- if (!m_type) {
435
- pybind11_fail (" Internal error: " + std::string (called)
436
- + " called while "
437
- " Python error indicator not set." );
438
- }
439
- const char *exc_type_name_orig = detail::obj_class_name (m_type.ptr ());
440
- if (exc_type_name_orig == nullptr ) {
441
- pybind11_fail (" Internal error: " + std::string (called)
442
- + " failed to obtain the name "
443
- " of the original active exception type." );
444
- }
445
- m_lazy_error_string = exc_type_name_orig;
446
- // PyErr_NormalizeException() may change the exception type if there are cascading
447
- // failures. This can potentially be extremely confusing.
448
- PyErr_NormalizeException (&m_type.ptr (), &m_value.ptr (), &m_trace.ptr ());
449
- if (m_type.ptr () == nullptr ) {
450
- pybind11_fail (" Internal error: " + std::string (called)
451
- + " failed to normalize the "
452
- " active exception." );
453
- }
454
- const char *exc_type_name_norm = detail::obj_class_name (m_type.ptr ());
455
- if (exc_type_name_orig == nullptr ) {
456
- pybind11_fail (" Internal error: " + std::string (called)
457
- + " failed to obtain the name "
458
- " of the normalized active exception type." );
459
- }
460
- if (exc_type_name_norm != m_lazy_error_string) {
461
- std::string msg = std::string (called)
462
- + " : MISMATCH of original and normalized "
463
- " active exception types: " ;
464
- msg += " ORIGINAL " ;
465
- msg += m_lazy_error_string;
466
- msg += " REPLACED BY " ;
467
- msg += exc_type_name_norm;
468
- msg += " : " + format_value_and_trace ();
469
- pybind11_fail (msg);
470
- }
471
- }
472
-
473
- error_fetch_and_normalize (const error_fetch_and_normalize &) = delete ;
474
- error_fetch_and_normalize (error_fetch_and_normalize &&) = delete ;
475
-
476
- std::string format_value_and_trace () const {
477
- std::string result;
478
- std::string message_error_string;
479
- if (m_value) {
480
- auto value_str = reinterpret_steal<object>(PyObject_Str (m_value.ptr ()));
481
- if (!value_str) {
482
- message_error_string = detail::error_string ();
483
- result = " <MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>" ;
484
- } else {
485
- result = value_str.cast <std::string>();
486
- }
487
- } else {
488
- result = " <MESSAGE UNAVAILABLE>" ;
489
- }
490
- if (result.empty ()) {
491
- result = " <EMPTY MESSAGE>" ;
492
- }
493
-
494
- bool have_trace = false ;
495
- if (m_trace) {
496
- #if !defined(PYPY_VERSION)
497
- auto *tb = reinterpret_cast <PyTracebackObject *>(m_trace.ptr ());
498
-
499
- // Get the deepest trace possible.
500
- while (tb->tb_next ) {
501
- tb = tb->tb_next ;
502
- }
503
-
504
- PyFrameObject *frame = tb->tb_frame ;
505
- Py_XINCREF (frame);
506
- result += " \n\n At:\n " ;
507
- while (frame) {
508
- # if PY_VERSION_HEX >= 0x030900B1
509
- PyCodeObject *f_code = PyFrame_GetCode (frame);
510
- # else
511
- PyCodeObject *f_code = frame->f_code ;
512
- Py_INCREF (f_code);
513
- # endif
514
- int lineno = PyFrame_GetLineNumber (frame);
515
- result += " " ;
516
- result += handle (f_code->co_filename ).cast <std::string>();
517
- result += ' (' ;
518
- result += std::to_string (lineno);
519
- result += " ): " ;
520
- result += handle (f_code->co_name ).cast <std::string>();
521
- result += ' \n ' ;
522
- Py_DECREF (f_code);
523
- # if PY_VERSION_HEX >= 0x030900B1
524
- auto *b_frame = PyFrame_GetBack (frame);
525
- # else
526
- auto *b_frame = frame->f_back ;
527
- Py_XINCREF (b_frame);
528
- # endif
529
- Py_DECREF (frame);
530
- frame = b_frame;
531
- }
532
-
533
- have_trace = true ;
534
- #endif // ! defined(PYPY_VERSION)
535
- }
536
-
537
- if (!message_error_string.empty ()) {
538
- if (!have_trace) {
539
- result += ' \n ' ;
540
- }
541
- result += " \n MESSAGE UNAVAILABLE DUE TO EXCEPTION: " + message_error_string;
542
- }
543
-
544
- return result;
545
- }
546
-
547
- std::string const &error_string () const {
548
- if (!m_lazy_error_string_completed) {
549
- m_lazy_error_string += " : " + format_value_and_trace ();
550
- m_lazy_error_string_completed = true ;
551
- }
552
- return m_lazy_error_string;
553
- }
554
-
555
- void restore () {
556
- if (m_restore_called) {
557
- pybind11_fail (" Internal error: pybind11::detail::error_fetch_and_normalize::restore() "
558
- " called a second time. ORIGINAL ERROR: "
559
- + error_string ());
560
- }
561
- PyErr_Restore (m_type.inc_ref ().ptr (), m_value.inc_ref ().ptr (), m_trace.inc_ref ().ptr ());
562
- m_restore_called = true ;
563
- }
564
-
565
- bool matches (handle exc) const {
566
- return (PyErr_GivenExceptionMatches (m_type.ptr (), exc.ptr ()) != 0 );
567
- }
568
-
569
- // Not protecting these for simplicity.
570
- object m_type, m_value, m_trace;
571
-
572
- private:
573
- // Only protecting invariants.
574
- mutable std::string m_lazy_error_string;
575
- mutable bool m_lazy_error_string_completed = false ;
576
- mutable bool m_restore_called = false ;
577
- };
578
-
579
- inline std::string error_string () {
580
- return error_fetch_and_normalize (" pybind11::detail::error_string" ).error_string ();
581
- }
582
-
414
+ std::string error_string(const char *called = nullptr );
583
415
PYBIND11_NAMESPACE_END (detail)
584
416
585
417
#if defined(_MSC_VER)
@@ -592,30 +424,39 @@ PYBIND11_NAMESPACE_END(detail)
592
424
// / thrown to propagate python-side errors back through C++ which can either be caught manually or
593
425
// / else falls back to the function dispatcher (which then raises the captured error back to
594
426
// / python).
595
- class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::exception {
427
+ class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error {
596
428
public:
597
- // / Fetches the current Python exception (using PyErr_Fetch()), which will clear the
598
- // / current Python error indicator.
599
- error_already_set ()
600
- : m_fetched_error{new detail::error_fetch_and_normalize (" pybind11::error_already_set" ),
601
- m_fetched_error_deleter} {}
602
-
603
- // / The what() result is built lazily on demand.
604
- // / WARNING: This member function needs to acquire the Python GIL. This can lead to
429
+ // / Constructs a new exception from the current Python error indicator. The current
430
+ // / Python error indicator will be cleared.
431
+ error_already_set () : std::runtime_error(detail::error_string(" pybind11::error_already_set" )) {
432
+ PyErr_Fetch (&m_type.ptr (), &m_value.ptr (), &m_trace.ptr ());
433
+ }
434
+
435
+ // / WARNING: The GIL must be held when this copy constructor is invoked!
436
+ error_already_set (const error_already_set &) = default ;
437
+ error_already_set (error_already_set &&) = default ;
438
+
439
+ // / WARNING: This destructor needs to acquire the Python GIL. This can lead to
605
440
// / crashes (undefined behavior) if the Python interpreter is finalizing.
606
- const char * what () const noexcept override ;
441
+ inline ~error_already_set () override ;
607
442
608
443
// / Restores the currently-held Python error (which will clear the Python error indicator first
609
- // / if already set).
444
+ // / if already set). After this call, the current object no longer stores the error variables.
445
+ // / NOTE: Any copies of this object may still store the error variables. Currently there is no
446
+ // protection against calling restore() from multiple copies.
610
447
// / NOTE: This member function will always restore the normalized exception, which may or may
611
448
// / not be the original Python exception.
612
449
// / WARNING: The GIL must be held when this member function is called!
613
- void restore () { m_fetched_error->restore (); }
450
+ void restore () {
451
+ PyErr_Restore (m_type.release ().ptr (), m_value.release ().ptr (), m_trace.release ().ptr ());
452
+ }
614
453
615
454
// / If it is impossible to raise the currently-held error, such as in a destructor, we can
616
455
// / write it out using Python's unraisable hook (`sys.unraisablehook`). The error context
617
456
// / should be some object whose `repr()` helps identify the location of the error. Python
618
- // / already knows the type and value of the error, so there is no need to repeat that.
457
+ // / already knows the type and value of the error, so there is no need to repeat that. After
458
+ // / this call, the current object no longer stores the error variables, and neither does
459
+ // / Python.
619
460
void discard_as_unraisable (object err_context) {
620
461
restore ();
621
462
PyErr_WriteUnraisable (err_context.ptr ());
@@ -634,18 +475,16 @@ class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::exception {
634
475
// / Check if the currently trapped error type matches the given Python exception class (or a
635
476
// / subclass thereof). May also be passed a tuple to search for any exception class matches in
636
477
// / the given tuple.
637
- bool matches (handle exc) const { return m_fetched_error->matches (exc); }
478
+ bool matches (handle exc) const {
479
+ return (PyErr_GivenExceptionMatches (m_type.ptr (), exc.ptr ()) != 0 );
480
+ }
638
481
639
- const object &type () const { return m_fetched_error-> m_type ; }
640
- const object &value () const { return m_fetched_error-> m_value ; }
641
- const object &trace () const { return m_fetched_error-> m_trace ; }
482
+ const object &type () const { return m_type; }
483
+ const object &value () const { return m_value; }
484
+ const object &trace () const { return m_trace; }
642
485
643
486
private:
644
- std::shared_ptr<detail::error_fetch_and_normalize> m_fetched_error;
645
-
646
- // / WARNING: This custom deleter needs to acquire the Python GIL. This can lead to
647
- // / crashes (undefined behavior) if the Python interpreter is finalizing.
648
- static void m_fetched_error_deleter (detail::error_fetch_and_normalize *raw_ptr);
487
+ object m_type, m_value, m_trace;
649
488
};
650
489
#if defined(_MSC_VER)
651
490
# pragma warning(pop)
@@ -681,7 +520,8 @@ inline void raise_from(PyObject *type, const char *message) {
681
520
682
521
// / Sets the current Python error indicator with the chosen error, performing a 'raise from'
683
522
// / from the error contained in error_already_set to indicate that the chosen error was
684
- // / caused by the original error.
523
+ // / caused by the original error. After this function is called error_already_set will
524
+ // / no longer contain an error.
685
525
inline void raise_from (error_already_set &err, PyObject *type, const char *message) {
686
526
err.restore ();
687
527
raise_from (type, message);
0 commit comments