@@ -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,39 @@ _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 ) {
594-         Py_SETREF (exc , code );
595-         if  (exc  ==  Py_None ) {
596-             goto done ;
597-         }
611+     if  (code  ==  NULL ) {
612+         // If the exception has no 'code' attribute, print the exception below 
613+         PyErr_Clear ();
598614    }
599-     /* If we failed to dig out the 'code' attribute, 
600-      * just let the else clause below print the error. 
601-      */ 
602- 
603-     if  (PyLong_Check (exc )) {
604-         exitcode  =  (int )PyLong_AsLong (exc );
615+     else  if  (parse_exit_code (code , exitcode_p )) {
616+         Py_DECREF (code );
617+         Py_CLEAR (exc );
618+         return  1 ;
605619    }
606620    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 );
619-         }
620-         PySys_WriteStderr ("\n" );
621-         exitcode  =  1 ;
621+         // If code is not an int or None, print it below 
622+         Py_SETREF (exc , code );
622623    }
623624
624- done :
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+         }
631+     } else  {
632+         if  (PyObject_Print (exc , stderr , Py_PRINT_RAW ) <  0 ) {
633+             PyErr_Clear ();
634+         }
635+         fflush (stderr );
636+     }
637+     PySys_WriteStderr ("\n" );
625638    Py_CLEAR (exc );
626-     * exitcode_p  =  exitcode ;
639+     * exitcode_p  =  1 ;
627640    return  1 ;
628641}
629642
0 commit comments