Skip to content

Commit 9275583

Browse files
committed
bpo-45711: make decisions based on exc_value instead of exc_type. Strengthen redundancy assertion for NULL/None.
1 parent c94664c commit 9275583

File tree

5 files changed

+76
-18
lines changed

5 files changed

+76
-18
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: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ static void
11001100
_assert_exception_type_is_redundant(PyObject* type, PyObject* val)
11011101
{
11021102
if (type == NULL || type == Py_None) {
1103-
assert(val == NULL || val == Py_None);
1103+
assert(val == type);
11041104
}
11051105
else {
11061106
assert(PyExceptionInstance_Check(val));
@@ -3661,7 +3661,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
36613661
"inherit from BaseException is not "
36623662
"allowed";
36633663
PyObject *right = POP();
3664-
PyObject *left = TOP();
3664+
ASSERT_EXC_TYPE_IS_REDUNDANT(TOP(), SECOND());
3665+
PyObject *left = SECOND();
3666+
assert(PyExceptionInstance_Check(left));
3667+
36653668
if (PyTuple_Check(right)) {
36663669
Py_ssize_t i, length;
36673670
length = PyTuple_GET_SIZE(right);
@@ -4138,7 +4141,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
41384141
ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
41394142
_PyErr_StackItem *exc_info = tstate->exc_info;
41404143
SET_THIRD(exc_info->exc_traceback);
4141-
SET_SECOND(exc_info->exc_value);
4144+
if (exc_info->exc_value != NULL) {
4145+
SET_SECOND(exc_info->exc_value);
4146+
}
4147+
else {
4148+
Py_INCREF(Py_None);
4149+
SET_SECOND(Py_None);
4150+
}
41424151
if (exc_info->exc_type != NULL) {
41434152
SET_TOP(exc_info->exc_type);
41444153
}
@@ -5843,7 +5852,9 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
58435852
type = exc_info->exc_type;
58445853
value = exc_info->exc_value;
58455854
tb = exc_info->exc_traceback;
5846-
if (Py_IsNone(type) || type == NULL) {
5855+
assert(((Py_IsNone(value) || value == NULL)) ==
5856+
((Py_IsNone(type) || type == NULL)));
5857+
if (Py_IsNone(value) || value == NULL) {
58475858
_PyErr_SetString(tstate, PyExc_RuntimeError,
58485859
"No active exception to reraise");
58495860
return 0;

Python/errors.c

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,15 @@ _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+
while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
8383
exc_info->previous_item != NULL)
8484
{
85+
assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
8586
exc_info = exc_info->previous_item;
8687
}
88+
assert(exc_info == NULL ||
89+
exc_info->previous_item == NULL ||
90+
(exc_info->exc_type != NULL && exc_info->exc_type != Py_None));
8791
return exc_info;
8892
}
8993

@@ -471,10 +475,25 @@ _PyErr_GetExcInfo(PyThreadState *tstate,
471475
PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
472476
{
473477
_PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate);
474-
*p_type = exc_info->exc_type;
478+
475479
*p_value = exc_info->exc_value;
476480
*p_traceback = exc_info->exc_traceback;
477481

482+
assert(*p_value == NULL ||
483+
*p_value == Py_None ||
484+
PyExceptionInstance_Check(*p_value));
485+
486+
*p_type = (*p_value != NULL && PyExceptionInstance_Check(*p_value)) ?
487+
PyExceptionInstance_Class(*p_value) :
488+
Py_None;
489+
490+
if (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) {
491+
assert(*p_type == Py_None);
492+
}
493+
else {
494+
assert(*p_type == exc_info->exc_type);
495+
}
496+
478497
Py_XINCREF(*p_type);
479498
Py_XINCREF(*p_value);
480499
Py_XINCREF(*p_traceback);
@@ -507,6 +526,30 @@ PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback)
507526
Py_XDECREF(oldtraceback);
508527
}
509528

529+
530+
PyObject*
531+
_PyErr_StackItemToExcInfoTuple(_PyErr_StackItem *err_info)
532+
{
533+
PyObject *exc_value = err_info->exc_value;
534+
if (exc_value == NULL) {
535+
exc_value = Py_None;
536+
}
537+
538+
assert(exc_value == Py_None || PyExceptionInstance_Check(exc_value));
539+
540+
PyObject *exc_type = PyExceptionInstance_Check(exc_value) ?
541+
PyExceptionInstance_Class(err_info->exc_value) :
542+
Py_None;
543+
544+
return Py_BuildValue(
545+
"(OOO)",
546+
exc_type,
547+
exc_value,
548+
err_info->exc_traceback != NULL ?
549+
err_info->exc_traceback : Py_None);
550+
}
551+
552+
510553
/* Like PyErr_Restore(), but if an exception is already set,
511554
set the context associated with it.
512555
@@ -567,7 +610,11 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
567610
} else {
568611
exc_info_given = 1;
569612
}
570-
if (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) {
613+
614+
assert( (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) ==
615+
(exc_info->exc_value == NULL || exc_info->exc_value == Py_None) );
616+
617+
if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) {
571618
return;
572619
}
573620

@@ -586,7 +633,14 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
586633
exc2 = exc_info->exc_type;
587634
val2 = exc_info->exc_value;
588635
tb2 = exc_info->exc_traceback;
636+
PyObject *exc2_before = exc2;
637+
PyObject *val2_before = val2;
638+
PyObject *tb2_before = tb2;
589639
_PyErr_NormalizeException(tstate, &exc2, &val2, &tb2);
640+
/* exc_info should already be normalized */
641+
assert(exc2 == exc2_before);
642+
assert(val2 == val2_before);
643+
assert(tb2 == tb2_before);
590644
if (tb2 != NULL) {
591645
PyException_SetTraceback(val2, tb2);
592646
}

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)