@@ -563,6 +563,30 @@ PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
563563 return _PyRun_SimpleStringFlagsWithName (command , NULL , flags );
564564}
565565
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+
566590int
567591_Py_HandleSystemExit (int * exitcode_p )
568592{
@@ -579,50 +603,40 @@ _Py_HandleSystemExit(int *exitcode_p)
579603
580604 fflush (stdout );
581605
582- int exitcode = 0 ;
583-
584606 PyObject * exc = PyErr_GetRaisedException ();
585- if (exc == NULL ) {
586- goto done ;
587- }
588- assert (PyExceptionInstance_Check (exc ));
607+ assert (exc != NULL && PyExceptionInstance_Check (exc ));
589608
590- /* The error code should be in the `code' attribute. */
591609 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
593621 Py_SETREF (exc , code );
594- if (exc == Py_None ) {
595- goto done ;
596- }
597622 }
598- /* If we failed to dig out the 'code' attribute,
599- * just let the else clause below print the error.
600- */
601623
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+ }
604630 }
605631 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 ();
618634 }
619- PySys_WriteStderr ("\n" );
620- exitcode = 1 ;
635+ fflush (stderr );
621636 }
622-
623- done :
637+ PySys_WriteStderr ("\n" );
624638 Py_CLEAR (exc );
625- * exitcode_p = exitcode ;
639+ * exitcode_p = 1 ;
626640 return 1 ;
627641}
628642
0 commit comments