Skip to content

Commit c456dfa

Browse files
authored
bpo-45711: use exc_value instead of exc_type to determine if exc_info is valid. Add more assertions. (GH-29627)
1 parent 24c10d2 commit c456dfa

File tree

5 files changed

+93
-36
lines changed

5 files changed

+93
-36
lines changed

Include/internal/pycore_pyerrors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state)
2828
Py_XDECREF(tb);
2929
}
3030

31+
PyAPI_FUNC(PyObject*) _PyErr_StackItemToExcInfoTuple(
32+
_PyErr_StackItem *err_info);
3133

3234
PyAPI_FUNC(void) _PyErr_Fetch(
3335
PyThreadState *tstate,

Python/ceval.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,7 +1102,7 @@ static void
11021102
_assert_exception_type_is_redundant(PyObject* type, PyObject* val)
11031103
{
11041104
if (type == NULL || type == Py_None) {
1105-
assert(val == NULL || val == Py_None);
1105+
assert(val == type);
11061106
}
11071107
else {
11081108
assert(PyExceptionInstance_Check(val));
@@ -3738,7 +3738,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
37383738

37393739
TARGET(JUMP_IF_NOT_EXC_MATCH) {
37403740
PyObject *right = POP();
3741-
PyObject *left = TOP();
3741+
ASSERT_EXC_TYPE_IS_REDUNDANT(TOP(), SECOND());
3742+
PyObject *left = SECOND();
3743+
assert(PyExceptionInstance_Check(left));
37423744
if (check_except_type_valid(tstate, right) < 0) {
37433745
Py_DECREF(right);
37443746
goto error;
@@ -4198,7 +4200,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
41984200
ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
41994201
_PyErr_StackItem *exc_info = tstate->exc_info;
42004202
SET_THIRD(exc_info->exc_traceback);
4201-
SET_SECOND(exc_info->exc_value);
4203+
if (exc_info->exc_value != NULL) {
4204+
SET_SECOND(exc_info->exc_value);
4205+
}
4206+
else {
4207+
Py_INCREF(Py_None);
4208+
SET_SECOND(Py_None);
4209+
}
42024210
if (exc_info->exc_type != NULL) {
42034211
SET_TOP(exc_info->exc_type);
42044212
}
@@ -5916,7 +5924,9 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
59165924
type = exc_info->exc_type;
59175925
value = exc_info->exc_value;
59185926
tb = exc_info->exc_traceback;
5919-
if (Py_IsNone(type) || type == NULL) {
5927+
assert(((Py_IsNone(value) || value == NULL)) ==
5928+
((Py_IsNone(type) || type == NULL)));
5929+
if (Py_IsNone(value) || value == NULL) {
59205930
_PyErr_SetString(tstate, PyExc_RuntimeError,
59215931
"No active exception to reraise");
59225932
return 0;

Python/errors.c

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,16 @@ _PyErr_StackItem *
7979
_PyErr_GetTopmostException(PyThreadState *tstate)
8080
{
8181
_PyErr_StackItem *exc_info = tstate->exc_info;
82-
while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) &&
82+
assert(exc_info);
83+
84+
while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
8385
exc_info->previous_item != NULL)
8486
{
87+
assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
8588
exc_info = exc_info->previous_item;
8689
}
90+
assert(exc_info->previous_item == NULL ||
91+
(exc_info->exc_type != NULL && exc_info->exc_type != Py_None));
8792
return exc_info;
8893
}
8994

@@ -471,10 +476,20 @@ _PyErr_GetExcInfo(PyThreadState *tstate,
471476
PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
472477
{
473478
_PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate);
474-
*p_type = exc_info->exc_type;
479+
475480
*p_value = exc_info->exc_value;
476481
*p_traceback = exc_info->exc_traceback;
477482

483+
if (*p_value == NULL || *p_value == Py_None) {
484+
assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
485+
*p_type = Py_None;
486+
}
487+
else {
488+
assert(PyExceptionInstance_Check(*p_value));
489+
assert(exc_info->exc_type == PyExceptionInstance_Class(*p_value));
490+
*p_type = PyExceptionInstance_Class(*p_value);
491+
}
492+
478493
Py_XINCREF(*p_type);
479494
Py_XINCREF(*p_value);
480495
Py_XINCREF(*p_traceback);
@@ -507,42 +522,66 @@ PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback)
507522
Py_XDECREF(oldtraceback);
508523
}
509524

525+
526+
PyObject*
527+
_PyErr_StackItemToExcInfoTuple(_PyErr_StackItem *err_info)
528+
{
529+
PyObject *exc_value = err_info->exc_value;
530+
if (exc_value == NULL) {
531+
exc_value = Py_None;
532+
}
533+
534+
assert(exc_value == Py_None || PyExceptionInstance_Check(exc_value));
535+
536+
PyObject *exc_type = PyExceptionInstance_Check(exc_value) ?
537+
PyExceptionInstance_Class(exc_value) :
538+
Py_None;
539+
540+
return Py_BuildValue(
541+
"(OOO)",
542+
exc_type,
543+
exc_value,
544+
err_info->exc_traceback != NULL ?
545+
err_info->exc_traceback : Py_None);
546+
}
547+
548+
510549
/* Like PyErr_Restore(), but if an exception is already set,
511550
set the context associated with it.
512551
513552
The caller is responsible for ensuring that this call won't create
514553
any cycles in the exception context chain. */
515554
void
516-
_PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb)
555+
_PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb)
517556
{
518-
if (exc == NULL)
557+
if (typ == NULL)
519558
return;
520559

521560
PyThreadState *tstate = _PyThreadState_GET();
522561

523-
if (!PyExceptionClass_Check(exc)) {
562+
if (!PyExceptionClass_Check(typ)) {
524563
_PyErr_Format(tstate, PyExc_SystemError,
525564
"_PyErr_ChainExceptions: "
526565
"exception %R is not a BaseException subclass",
527-
exc);
566+
typ);
528567
return;
529568
}
530569

531570
if (_PyErr_Occurred(tstate)) {
532-
PyObject *exc2, *val2, *tb2;
533-
_PyErr_Fetch(tstate, &exc2, &val2, &tb2);
534-
_PyErr_NormalizeException(tstate, &exc, &val, &tb);
571+
PyObject *typ2, *val2, *tb2;
572+
_PyErr_Fetch(tstate, &typ2, &val2, &tb2);
573+
_PyErr_NormalizeException(tstate, &typ, &val, &tb);
535574
if (tb != NULL) {
536575
PyException_SetTraceback(val, tb);
537576
Py_DECREF(tb);
538577
}
539-
Py_DECREF(exc);
540-
_PyErr_NormalizeException(tstate, &exc2, &val2, &tb2);
578+
Py_DECREF(typ);
579+
_PyErr_NormalizeException(tstate, &typ2, &val2, &tb2);
541580
PyException_SetContext(val2, val);
542-
_PyErr_Restore(tstate, exc2, val2, tb2);
581+
_PyErr_Restore(tstate, typ2, val2, tb2);
543582
}
544583
else {
545-
_PyErr_Restore(tstate, exc, val, tb);
584+
_PyErr_Restore(tstate, typ, val, tb);
546585
}
547586
}
548587

@@ -567,7 +606,11 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
567606
} else {
568607
exc_info_given = 1;
569608
}
570-
if (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) {
609+
610+
assert( (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) ==
611+
(exc_info->exc_value == NULL || exc_info->exc_value == Py_None) );
612+
613+
if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) {
571614
return;
572615
}
573616

@@ -579,21 +622,32 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
579622
tstate->exc_info = exc_info;
580623
}
581624

582-
PyObject *exc, *val, *tb;
583-
_PyErr_Fetch(tstate, &exc, &val, &tb);
625+
PyObject *typ, *val, *tb;
626+
_PyErr_Fetch(tstate, &typ, &val, &tb);
584627

585-
PyObject *exc2, *val2, *tb2;
586-
exc2 = exc_info->exc_type;
628+
PyObject *typ2, *val2, *tb2;
629+
typ2 = exc_info->exc_type;
587630
val2 = exc_info->exc_value;
588631
tb2 = exc_info->exc_traceback;
589-
_PyErr_NormalizeException(tstate, &exc2, &val2, &tb2);
632+
#ifdef Py_DEBUG
633+
PyObject *typ2_before = typ2;
634+
PyObject *val2_before = val2;
635+
PyObject *tb2_before = tb2;
636+
#endif
637+
_PyErr_NormalizeException(tstate, &typ2, &val2, &tb2);
638+
#ifdef Py_DEBUG
639+
/* exc_info should already be normalized */
640+
assert(typ2 == typ2_before);
641+
assert(val2 == val2_before);
642+
assert(tb2 == tb2_before);
643+
#endif
590644
if (tb2 != NULL) {
591645
PyException_SetTraceback(val2, tb2);
592646
}
593647

594648
/* _PyErr_SetObject sets the context from PyThreadState. */
595-
_PyErr_SetObject(tstate, exc, val);
596-
Py_DECREF(exc); // since _PyErr_Occurred was true
649+
_PyErr_SetObject(tstate, typ, val);
650+
Py_DECREF(typ); // since _PyErr_Occurred was true
597651
Py_XDECREF(val);
598652
Py_XDECREF(tb);
599653

Python/pystate.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,11 +1341,7 @@ _PyThread_CurrentExceptions(void)
13411341
if (id == NULL) {
13421342
goto fail;
13431343
}
1344-
PyObject *exc_info = PyTuple_Pack(
1345-
3,
1346-
err_info->exc_type != NULL ? err_info->exc_type : Py_None,
1347-
err_info->exc_value != NULL ? err_info->exc_value : Py_None,
1348-
err_info->exc_traceback != NULL ? err_info->exc_traceback : Py_None);
1344+
PyObject *exc_info = _PyErr_StackItemToExcInfoTuple(err_info);
13491345
if (exc_info == NULL) {
13501346
Py_DECREF(id);
13511347
goto fail;

Python/sysmodule.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -785,12 +785,7 @@ sys_exc_info_impl(PyObject *module)
785785
/*[clinic end generated code: output=3afd0940cf3a4d30 input=b5c5bf077788a3e5]*/
786786
{
787787
_PyErr_StackItem *err_info = _PyErr_GetTopmostException(_PyThreadState_GET());
788-
return Py_BuildValue(
789-
"(OOO)",
790-
err_info->exc_type != NULL ? err_info->exc_type : Py_None,
791-
err_info->exc_value != NULL ? err_info->exc_value : Py_None,
792-
err_info->exc_traceback != NULL ?
793-
err_info->exc_traceback : Py_None);
788+
return _PyErr_StackItemToExcInfoTuple(err_info);
794789
}
795790

796791

0 commit comments

Comments
 (0)