@@ -564,6 +564,30 @@ PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
564564 return _PyRun_SimpleStringFlagsWithName (command , NULL , flags );
565565}
566566
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+
567591int
568592_Py_HandleSystemExit (int * exitcode_p )
569593{
@@ -580,50 +604,40 @@ _Py_HandleSystemExit(int *exitcode_p)
580604
581605 fflush (stdout );
582606
583- int exitcode = 0 ;
584-
585607 PyObject * exc = PyErr_GetRaisedException ();
586- if (exc == NULL ) {
587- goto done ;
588- }
589- assert (PyExceptionInstance_Check (exc ));
608+ assert (exc != NULL && PyExceptionInstance_Check (exc ));
590609
591- /* The error code should be in the `code' attribute. */
592610 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
594622 Py_SETREF (exc , code );
595- if (exc == Py_None ) {
596- goto done ;
597- }
598623 }
599- /* If we failed to dig out the 'code' attribute,
600- * just let the else clause below print the error.
601- */
602624
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+ }
605631 }
606632 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 ();
619635 }
620- PySys_WriteStderr ("\n" );
621- exitcode = 1 ;
636+ fflush (stderr );
622637 }
623-
624- done :
638+ PySys_WriteStderr ("\n" );
625639 Py_CLEAR (exc );
626- * exitcode_p = exitcode ;
640+ * exitcode_p = 1 ;
627641 return 1 ;
628642}
629643
0 commit comments