@@ -629,14 +629,18 @@ parse_syntax_error(PyObject *err, PyObject **message, PyObject **filename,
629629 return 0 ;
630630}
631631
632- static void
633- print_error_text (PyObject * f , Py_ssize_t offset , Py_ssize_t end_offset , PyObject * text_obj )
632+ static int
633+ print_error_text (PyObject * f , Py_ssize_t offset , Py_ssize_t end_offset ,
634+ PyObject * text_obj )
634635{
635- size_t caret_repetitions = (end_offset > 0 && end_offset > offset ) ? end_offset - offset : 1 ;
636+ size_t caret_repetitions = (end_offset > 0 && end_offset > offset ) ?
637+ end_offset - offset : 1 ;
638+
636639 /* Convert text to a char pointer; return if error */
637640 const char * text = PyUnicode_AsUTF8 (text_obj );
638- if (text == NULL )
639- return ;
641+ if (text == NULL ) {
642+ return -1 ;
643+ }
640644
641645 /* Convert offset from 1-based to 0-based */
642646 offset -- ;
@@ -675,27 +679,43 @@ print_error_text(PyObject *f, Py_ssize_t offset, Py_ssize_t end_offset, PyObject
675679 }
676680
677681 /* Print text */
678- PyFile_WriteString (" " , f );
679- PyFile_WriteString (text , f );
682+ if (PyFile_WriteString (" " , f ) < 0 ) {
683+ return -1 ;
684+ }
685+ if (PyFile_WriteString (text , f ) < 0 ) {
686+ return -1 ;
687+ }
680688
681689 /* Make sure there's a newline at the end */
682690 if (text [len ] != '\n' ) {
683- PyFile_WriteString ("\n" , f );
691+ if (PyFile_WriteString ("\n" , f ) < 0 ) {
692+ return -1 ;
693+ }
684694 }
685695
686696 /* Don't print caret if it points to the left of the text */
687- if (offset < 0 )
688- return ;
697+ if (offset < 0 ) {
698+ return 0 ;
699+ }
689700
690701 /* Write caret line */
691- PyFile_WriteString (" " , f );
702+ if (PyFile_WriteString (" " , f ) < 0 ) {
703+ return -1 ;
704+ }
692705 while (-- offset >= 0 ) {
693- PyFile_WriteString (" " , f );
706+ if (PyFile_WriteString (" " , f ) < 0 ) {
707+ return -1 ;
708+ }
694709 }
695710 for (size_t caret_iter = 0 ; caret_iter < caret_repetitions ; caret_iter ++ ) {
696- PyFile_WriteString ("^" , f );
711+ if (PyFile_WriteString ("^" , f ) < 0 ) {
712+ return -1 ;
713+ }
714+ }
715+ if (PyFile_WriteString ("\n" , f ) < 0 ) {
716+ return -1 ;
697717 }
698- PyFile_WriteString ( "\n" , f ) ;
718+ return 0 ;
699719}
700720
701721
@@ -953,6 +973,77 @@ print_exception_traceback(struct exception_print_context *ctx, PyObject *value)
953973 return err ;
954974}
955975
976+ static int
977+ print_exception_file_and_line (struct exception_print_context * ctx ,
978+ PyObject * * value_p )
979+ {
980+ PyObject * f = ctx -> file ;
981+
982+ _Py_IDENTIFIER (print_file_and_line );
983+ PyObject * tmp ;
984+ int res = _PyObject_LookupAttrId (* value_p , & PyId_print_file_and_line , & tmp );
985+ if (res <= 0 ) {
986+ if (res < 0 ) {
987+ PyErr_Clear ();
988+ }
989+ return 0 ;
990+ }
991+ Py_DECREF (tmp );
992+
993+ PyObject * message , * filename , * text ;
994+ Py_ssize_t lineno , offset , end_lineno , end_offset ;
995+ if (!parse_syntax_error (* value_p , & message , & filename ,
996+ & lineno , & offset ,
997+ & end_lineno , & end_offset , & text )) {
998+ PyErr_Clear ();
999+ return 0 ;
1000+ }
1001+
1002+ Py_SETREF (* value_p , message );
1003+
1004+ PyObject * line = PyUnicode_FromFormat (" File \"%S\", line %zd\n" ,
1005+ filename , lineno );
1006+ Py_DECREF (filename );
1007+ if (line == NULL ) {
1008+ goto error ;
1009+ }
1010+ if (write_indented_margin (ctx , f ) < 0 ) {
1011+ goto error ;
1012+ }
1013+ if (PyFile_WriteObject (line , f , Py_PRINT_RAW ) < 0 ) {
1014+ goto error ;
1015+ }
1016+ Py_CLEAR (line );
1017+
1018+ if (text != NULL ) {
1019+ Py_ssize_t line_size ;
1020+ const char * error_line = PyUnicode_AsUTF8AndSize (text , & line_size );
1021+ // If the location of the error spawn multiple lines, we want
1022+ // to just print the first one and highlight everything until
1023+ // the end of that one since we don't support multi-line error
1024+ // messages.
1025+ if (end_lineno > lineno ) {
1026+ end_offset = (error_line != NULL ) ? line_size : -1 ;
1027+ }
1028+ // Limit the amount of '^' that we can display to
1029+ // the size of the text in the source line.
1030+ if (error_line != NULL && end_offset > line_size + 1 ) {
1031+ end_offset = line_size + 1 ;
1032+ }
1033+ if (print_error_text (f , offset , end_offset , text ) < 0 ) {
1034+ goto error ;
1035+ }
1036+ Py_DECREF (text );
1037+ }
1038+ assert (!PyErr_Occurred ());
1039+ return 0 ;
1040+
1041+ error :
1042+ Py_XDECREF (line );
1043+ Py_XDECREF (text );
1044+ return -1 ;
1045+ }
1046+
9561047/* Prints the message line: module.qualname[: str(exc)] */
9571048static int
9581049print_exception_message (struct exception_print_context * ctx , PyObject * type ,
@@ -1072,6 +1163,11 @@ static int
10721163print_exception_note (struct exception_print_context * ctx , PyObject * value )
10731164{
10741165 PyObject * f = ctx -> file ;
1166+
1167+ if (!PyExceptionInstance_Check (value )) {
1168+ return 0 ;
1169+ }
1170+
10751171 _Py_IDENTIFIER (__note__ );
10761172
10771173 PyObject * note = _PyObject_GetAttrId (value , & PyId___note__ );
@@ -1112,98 +1208,47 @@ print_exception_note(struct exception_print_context *ctx, PyObject *value)
11121208 return -1 ;
11131209}
11141210
1115- static void
1211+ static int
11161212print_exception (struct exception_print_context * ctx , PyObject * value )
11171213{
1118- int err = 0 ;
1119- PyObject * tmp ;
11201214 PyObject * f = ctx -> file ;
11211215
1122- _Py_IDENTIFIER (print_file_and_line );
1123-
11241216 if (!PyExceptionInstance_Check (value )) {
1125- if (print_exception_invalid_type (ctx , value ) < 0 ) {
1126- PyErr_Clear (); /* TODO: change to return -1 */
1127- }
1128- return ;
1217+ return print_exception_invalid_type (ctx , value );
11291218 }
11301219
11311220 Py_INCREF (value );
11321221 fflush (stdout );
1133- PyObject * type = (PyObject * ) Py_TYPE (value );
1134- err = print_exception_traceback (ctx , value );
1135- if (err == 0 &&
1136- (err = _PyObject_LookupAttrId (value , & PyId_print_file_and_line , & tmp )) > 0 )
1137- {
1138- PyObject * message , * filename , * text ;
1139- Py_ssize_t lineno , offset , end_lineno , end_offset ;
1140- err = 0 ;
1141- Py_DECREF (tmp );
1142- if (!parse_syntax_error (value , & message , & filename ,
1143- & lineno , & offset ,
1144- & end_lineno , & end_offset , & text )) {
1145- PyErr_Clear ();
1146- }
1147- else {
11481222
1149- Py_DECREF (value );
1150- value = message ;
1151-
1152- PyObject * line = PyUnicode_FromFormat (" File \"%S\", line %zd\n" ,
1153- filename , lineno );
1154- Py_DECREF (filename );
1155- if (line != NULL ) {
1156- err = write_indented_margin (ctx , f );
1157- if (err == 0 ) {
1158- err = PyFile_WriteObject (line , f , Py_PRINT_RAW );
1159- }
1160- Py_DECREF (line );
1161- }
1223+ if (print_exception_traceback (ctx , value ) < 0 ) {
1224+ goto error ;
1225+ }
11621226
1163- if (text != NULL ) {
1164- Py_ssize_t line_size ;
1165- const char * error_line = PyUnicode_AsUTF8AndSize (text , & line_size );
1166- // If the location of the error spawn multiple lines, we want
1167- // to just print the first one and highlight everything until
1168- // the end of that one since we don't support multi-line error
1169- // messages.
1170- if (end_lineno > lineno ) {
1171- end_offset = (error_line != NULL ) ? line_size : -1 ;
1172- }
1173- // Limit the amount of '^' that we can display to
1174- // the size of the text in the source line.
1175- if (error_line != NULL && end_offset > line_size + 1 ) {
1176- end_offset = line_size + 1 ;
1177- }
1178- print_error_text (f , offset , end_offset , text );
1179- Py_DECREF (text );
1180- }
1227+ /* grab the type now because value can change below */
1228+ PyObject * type = (PyObject * ) Py_TYPE (value );
11811229
1182- /* Can't be bothered to check all those
1183- PyFile_WriteString() calls */
1184- if (PyErr_Occurred ())
1185- err = -1 ;
1186- }
1230+ if (print_exception_file_and_line (ctx , & value ) < 0 ) {
1231+ goto error ;
11871232 }
1188-
1189- if (err == 0 ) {
1190- err = print_exception_message (ctx , type , value );
1233+ if (print_exception_message (ctx , type , value ) < 0 ) {
1234+ goto error ;
11911235 }
1192- if (err == 0 ) {
1193- err = print_exception_suggestions ( ctx , value ) ;
1236+ if (print_exception_suggestions ( ctx , value ) < 0 ) {
1237+ goto error ;
11941238 }
1195- if (err == 0 ) {
1196- err = PyFile_WriteString ( "\n" , f ) ;
1239+ if (PyFile_WriteString ( "\n" , f ) < 0 ) {
1240+ goto error ;
11971241 }
1198- if (err == 0 && PyExceptionInstance_Check ( value )) {
1199- err = print_exception_note ( ctx , value ) ;
1242+ if (print_exception_note ( ctx , value ) < 0 ) {
1243+ goto error ;
12001244 }
12011245
12021246 Py_DECREF (value );
1203- /* If an error happened here, don't show it.
1204- XXX This is wrong, but too many callers rely on this behavior. */
1205- if (err != 0 )
1206- PyErr_Clear ();
1247+ assert (!PyErr_Occurred ());
1248+ return 0 ;
1249+ error :
1250+ Py_DECREF (value );
1251+ return -1 ;
12071252}
12081253
12091254static const char cause_message [] =
@@ -1214,7 +1259,7 @@ static const char context_message[] =
12141259 "During handling of the above exception, "
12151260 "another exception occurred:\n" ;
12161261
1217- static void
1262+ static int
12181263print_exception_recursive (struct exception_print_context * , PyObject * );
12191264
12201265static int
@@ -1227,10 +1272,12 @@ print_chained(struct exception_print_context* ctx, PyObject *value,
12271272 return -1 ;
12281273 }
12291274 bool need_close = ctx -> need_close ;
1230- print_exception_recursive (ctx , value );
1275+ int res = print_exception_recursive (ctx , value );
12311276 ctx -> need_close = need_close ;
1232-
12331277 Py_LeaveRecursiveCall ();
1278+ if (res < 0 ) {
1279+ return -1 ;
1280+ }
12341281
12351282 if (write_indented_margin (ctx , f ) < 0 ) {
12361283 return -1 ;
@@ -1398,11 +1445,14 @@ print_exception_group(struct exception_print_context *ctx, PyObject *value)
13981445 PyObject * exc = PyTuple_GET_ITEM (excs , i );
13991446
14001447 if (!truncated ) {
1401- if (Py_EnterRecursiveCall (" in print_exception_recursive " ) != 0 ) {
1448+ if (Py_EnterRecursiveCall (" in print_exception_group " ) != 0 ) {
14021449 return -1 ;
14031450 }
1404- print_exception_recursive (ctx , exc );
1451+ int res = print_exception_recursive (ctx , exc );
14051452 Py_LeaveRecursiveCall ();
1453+ if (res < 0 ) {
1454+ return -1 ;
1455+ }
14061456 }
14071457 else {
14081458 Py_ssize_t excs_remaining = num_excs - ctx -> max_group_width ;
@@ -1445,33 +1495,25 @@ print_exception_group(struct exception_print_context *ctx, PyObject *value)
14451495 return 0 ;
14461496}
14471497
1448- static void
1498+ static int
14491499print_exception_recursive (struct exception_print_context * ctx , PyObject * value )
14501500{
1451- int err = 0 ;
14521501 if (ctx -> seen != NULL ) {
14531502 /* Exception chaining */
1454- err = print_exception_cause_and_context (ctx , value );
1455- }
1456- if (err ) {
1457- /* don't do anything else */
1458- }
1459- else if (!_PyBaseExceptionGroup_Check (value )) {
1460- print_exception (ctx , value );
1461- }
1462- else {
1463- int prev_depth = ctx -> exception_group_depth ;
1464- err = print_exception_group (ctx , value );
1465- if (err < 0 ) {
1466- /* restore the depth as long as we're ignoring errors */
1467- ctx -> exception_group_depth = prev_depth ;
1503+ if (print_exception_cause_and_context (ctx , value ) < 0 ) {
1504+ return -1 ;
14681505 }
1469- else {
1470- assert (prev_depth == ctx -> exception_group_depth );
1506+ }
1507+ if (!_PyBaseExceptionGroup_Check (value )) {
1508+ if (print_exception (ctx , value ) < 0 ) {
1509+ return -1 ;
14711510 }
14721511 }
1473- if (err != 0 )
1474- PyErr_Clear ();
1512+ else if (print_exception_group (ctx , value ) < 0 ) {
1513+ return -1 ;
1514+ }
1515+ assert (!PyErr_Occurred ());
1516+ return 0 ;
14751517}
14761518
14771519#define PyErr_MAX_GROUP_WIDTH 15
@@ -1505,7 +1547,9 @@ _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *t
15051547 if (ctx .seen == NULL ) {
15061548 PyErr_Clear ();
15071549 }
1508- print_exception_recursive (& ctx , value );
1550+ if (print_exception_recursive (& ctx , value ) < 0 ) {
1551+ PyErr_Clear ();
1552+ }
15091553 Py_XDECREF (ctx .seen );
15101554
15111555 /* Call file.flush() */
0 commit comments