@@ -563,6 +563,30 @@ PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
563
563
return _PyRun_SimpleStringFlagsWithName (command , NULL , flags );
564
564
}
565
565
566
+ static int
567
+ parse_exit_code (PyObject * code , int * exitcode_p )
568
+ {
569
+ if (PyLong_Check (code )) {
570
+ // gh-125842: Use a long long to avoid an overflow error when `long`
571
+ // is 32-bit. We still truncate the result to an int.
572
+ int exitcode = (int )PyLong_AsLongLong (code );
573
+ if (exitcode == -1 && PyErr_Occurred ()) {
574
+ // On overflow or other error, clear the exception and use -1
575
+ // as the exit code to match historical Python behavior.
576
+ PyErr_Clear ();
577
+ * exitcode_p = -1 ;
578
+ return 1 ;
579
+ }
580
+ * exitcode_p = exitcode ;
581
+ return 1 ;
582
+ }
583
+ else if (code == Py_None ) {
584
+ * exitcode_p = 0 ;
585
+ return 1 ;
586
+ }
587
+ return 0 ;
588
+ }
589
+
566
590
int
567
591
_Py_HandleSystemExit (int * exitcode_p )
568
592
{
@@ -579,50 +603,40 @@ _Py_HandleSystemExit(int *exitcode_p)
579
603
580
604
fflush (stdout );
581
605
582
- int exitcode = 0 ;
583
-
584
606
PyObject * exc = PyErr_GetRaisedException ();
585
- if (exc == NULL ) {
586
- goto done ;
587
- }
588
- assert (PyExceptionInstance_Check (exc ));
607
+ assert (exc != NULL && PyExceptionInstance_Check (exc ));
589
608
590
- /* The error code should be in the `code' attribute. */
591
609
PyObject * code = PyObject_GetAttr (exc , & _Py_ID (code ));
592
- if (code ) {
610
+ if (code == NULL ) {
611
+ // If the exception has no 'code' attribute, print the exception below
612
+ PyErr_Clear ();
613
+ }
614
+ else if (parse_exit_code (code , exitcode_p )) {
615
+ Py_DECREF (code );
616
+ Py_CLEAR (exc );
617
+ return 1 ;
618
+ }
619
+ else {
620
+ // If code is not an int or None, print it below
593
621
Py_SETREF (exc , code );
594
- if (exc == Py_None ) {
595
- goto done ;
596
- }
597
622
}
598
- /* If we failed to dig out the 'code' attribute,
599
- * just let the else clause below print the error.
600
- */
601
623
602
- if (PyLong_Check (exc )) {
603
- exitcode = (int )PyLong_AsLong (exc );
624
+ PyThreadState * tstate = _PyThreadState_GET ();
625
+ PyObject * sys_stderr = _PySys_GetAttr (tstate , & _Py_ID (stderr ));
626
+ if (sys_stderr != NULL && sys_stderr != Py_None ) {
627
+ if (PyFile_WriteObject (exc , sys_stderr , Py_PRINT_RAW ) < 0 ) {
628
+ PyErr_Clear ();
629
+ }
604
630
}
605
631
else {
606
- PyThreadState * tstate = _PyThreadState_GET ();
607
- PyObject * sys_stderr = _PySys_GetAttr (tstate , & _Py_ID (stderr ));
608
- /* We clear the exception here to avoid triggering the assertion
609
- * in PyObject_Str that ensures it won't silently lose exception
610
- * details.
611
- */
612
- PyErr_Clear ();
613
- if (sys_stderr != NULL && sys_stderr != Py_None ) {
614
- PyFile_WriteObject (exc , sys_stderr , Py_PRINT_RAW );
615
- } else {
616
- PyObject_Print (exc , stderr , Py_PRINT_RAW );
617
- fflush (stderr );
632
+ if (PyObject_Print (exc , stderr , Py_PRINT_RAW ) < 0 ) {
633
+ PyErr_Clear ();
618
634
}
619
- PySys_WriteStderr ("\n" );
620
- exitcode = 1 ;
635
+ fflush (stderr );
621
636
}
622
-
623
- done :
637
+ PySys_WriteStderr ("\n" );
624
638
Py_CLEAR (exc );
625
- * exitcode_p = exitcode ;
639
+ * exitcode_p = 1 ;
626
640
return 1 ;
627
641
}
628
642
0 commit comments