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