@@ -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