@@ -58,7 +58,7 @@ BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
5858 if (!_PyArg_NoKeywords (Py_TYPE (self )-> tp_name , kwds ))
5959 return -1 ;
6060
61- Py_DECREF (self -> args );
61+ Py_XDECREF (self -> args );
6262 self -> args = args ;
6363 Py_INCREF (self -> args );
6464
@@ -587,37 +587,34 @@ SimpleExtendsException(PyExc_Exception, ImportError,
587587 * when it was supplied.
588588 */
589589
590- static PyObject *
591- OSError_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
592- {
593- PyOSErrorObject * self = NULL ;
594- Py_ssize_t nargs ;
595-
596- PyObject * myerrno = NULL , * strerror = NULL , * filename = NULL ;
597- PyObject * subslice = NULL ;
590+ /* This function doesn't cleanup on error, the caller should */
591+ static int
592+ oserror_parse_args (PyObject * * p_args ,
593+ PyObject * * myerrno , PyObject * * strerror ,
594+ PyObject * * filename
598595#ifdef MS_WINDOWS
599- PyObject * winerror = NULL ;
600- long winerrcode = 0 ;
596+ , PyObject * * winerror
601597#endif
598+ )
599+ {
600+ Py_ssize_t nargs ;
601+ PyObject * args = * p_args ;
602602
603- if (!_PyArg_NoKeywords (type -> tp_name , kwds ))
604- return NULL ;
605- Py_INCREF (args );
606603 nargs = PyTuple_GET_SIZE (args );
607604
608605#ifdef MS_WINDOWS
609606 if (nargs >= 2 && nargs <= 4 ) {
610607 if (!PyArg_UnpackTuple (args , "OSError" , 2 , 4 ,
611- & myerrno , & strerror , & filename , & winerror ))
612- goto error ;
613- if (winerror && PyLong_Check (winerror )) {
614- long errcode ;
608+ myerrno , strerror , filename , winerror ))
609+ return -1 ;
610+ if (* winerror && PyLong_Check (* winerror )) {
611+ long errcode , winerrcode ;
615612 PyObject * newargs ;
616613 Py_ssize_t i ;
617614
618- winerrcode = PyLong_AsLong (winerror );
615+ winerrcode = PyLong_AsLong (* winerror );
619616 if (winerrcode == -1 && PyErr_Occurred ())
620- goto error ;
617+ return -1 ;
621618 /* Set errno to the corresponding POSIX errno (overriding
622619 first argument). Windows Socket error codes (>= 10000)
623620 have the same value as their POSIX counterparts.
@@ -626,59 +623,55 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
626623 errcode = winerror_to_errno (winerrcode );
627624 else
628625 errcode = winerrcode ;
629- myerrno = PyLong_FromLong (errcode );
630- if (!myerrno )
631- goto error ;
626+ * myerrno = PyLong_FromLong (errcode );
627+ if (!* myerrno )
628+ return -1 ;
632629 newargs = PyTuple_New (nargs );
633630 if (!newargs )
634- goto error ;
635- PyTuple_SET_ITEM (newargs , 0 , myerrno );
631+ return -1 ;
632+ PyTuple_SET_ITEM (newargs , 0 , * myerrno );
636633 for (i = 1 ; i < nargs ; i ++ ) {
637634 PyObject * val = PyTuple_GET_ITEM (args , i );
638635 Py_INCREF (val );
639636 PyTuple_SET_ITEM (newargs , i , val );
640637 }
641638 Py_DECREF (args );
642- args = newargs ;
639+ args = * p_args = newargs ;
643640 }
644641 }
645642#else
646643 if (nargs >= 2 && nargs <= 3 ) {
647644 if (!PyArg_UnpackTuple (args , "OSError" , 2 , 3 ,
648- & myerrno , & strerror , & filename ))
649- goto error ;
645+ myerrno , strerror , filename ))
646+ return -1 ;
650647 }
651648#endif
652- if (myerrno && PyLong_Check (myerrno ) &&
653- errnomap && (PyObject * ) type == PyExc_OSError ) {
654- PyObject * newtype ;
655- newtype = PyDict_GetItem (errnomap , myerrno );
656- if (newtype ) {
657- assert (PyType_Check (newtype ));
658- type = (PyTypeObject * ) newtype ;
659- }
660- else if (PyErr_Occurred ())
661- goto error ;
662- }
663649
664- self = (PyOSErrorObject * ) type -> tp_alloc (type , 0 );
665- if (!self )
666- goto error ;
650+ return 0 ;
651+ }
667652
668- self -> dict = NULL ;
669- self -> traceback = self -> cause = self -> context = NULL ;
670- self -> written = -1 ;
653+ static int
654+ oserror_init (PyOSErrorObject * self , PyObject * * p_args ,
655+ PyObject * myerrno , PyObject * strerror ,
656+ PyObject * filename
657+ #ifdef MS_WINDOWS
658+ , PyObject * winerror
659+ #endif
660+ )
661+ {
662+ PyObject * args = * p_args ;
663+ Py_ssize_t nargs = PyTuple_GET_SIZE (args );
671664
672665 /* self->filename will remain Py_None otherwise */
673666 if (filename && filename != Py_None ) {
674- if (( PyObject * ) type == PyExc_BlockingIOError &&
667+ if (Py_TYPE ( self ) == ( PyTypeObject * ) PyExc_BlockingIOError &&
675668 PyNumber_Check (filename )) {
676669 /* BlockingIOError's 3rd argument can be the number of
677670 * characters written.
678671 */
679672 self -> written = PyNumber_AsSsize_t (filename , PyExc_ValueError );
680673 if (self -> written == -1 && PyErr_Occurred ())
681- goto error ;
674+ return -1 ;
682675 }
683676 else {
684677 Py_INCREF (filename );
@@ -687,20 +680,15 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
687680 if (nargs >= 2 && nargs <= 3 ) {
688681 /* filename is removed from the args tuple (for compatibility
689682 purposes, see test_exceptions.py) */
690- subslice = PyTuple_GetSlice (args , 0 , 2 );
683+ PyObject * subslice = PyTuple_GetSlice (args , 0 , 2 );
691684 if (!subslice )
692- goto error ;
685+ return -1 ;
693686
694687 Py_DECREF (args ); /* replacing args */
695- args = subslice ;
688+ * p_args = args = subslice ;
696689 }
697690 }
698691 }
699-
700- /* Steals the reference to args */
701- self -> args = args ;
702- args = NULL ;
703-
704692 Py_XINCREF (myerrno );
705693 self -> myerrno = myerrno ;
706694
@@ -712,6 +700,90 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
712700 self -> winerror = winerror ;
713701#endif
714702
703+ /* Steals the reference to args */
704+ self -> args = args ;
705+ args = NULL ;
706+
707+ return 0 ;
708+ }
709+
710+ static PyObject *
711+ OSError_new (PyTypeObject * type , PyObject * args , PyObject * kwds );
712+ static int
713+ OSError_init (PyOSErrorObject * self , PyObject * args , PyObject * kwds );
714+
715+ static int
716+ oserror_use_init (PyTypeObject * type )
717+ {
718+ /* When __init__ is defined in a OSError subclass, we want any
719+ extraneous argument to __new__ to be ignored. The only reasonable
720+ solution, given __new__ takes a variable number of arguments,
721+ is to defer arg parsing and initialization to __init__.
722+
723+ But when __new__ is overriden as well, it should call our __new__
724+ with the right arguments.
725+
726+ (see http://bugs.python.org/issue12555#msg148829 )
727+ */
728+ if (type -> tp_init != (initproc ) OSError_init &&
729+ type -> tp_new == (newfunc ) OSError_new ) {
730+ assert ((PyObject * ) type != PyExc_OSError );
731+ return 1 ;
732+ }
733+ return 0 ;
734+ }
735+
736+ static PyObject *
737+ OSError_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
738+ {
739+ PyOSErrorObject * self = NULL ;
740+ PyObject * myerrno = NULL , * strerror = NULL , * filename = NULL ;
741+ #ifdef MS_WINDOWS
742+ PyObject * winerror = NULL ;
743+ #endif
744+
745+ if (!oserror_use_init (type )) {
746+ if (!_PyArg_NoKeywords (type -> tp_name , kwds ))
747+ return NULL ;
748+
749+ Py_INCREF (args );
750+ if (oserror_parse_args (& args , & myerrno , & strerror , & filename
751+ #ifdef MS_WINDOWS
752+ , & winerror
753+ #endif
754+ ))
755+ goto error ;
756+
757+ if (myerrno && PyLong_Check (myerrno ) &&
758+ errnomap && (PyObject * ) type == PyExc_OSError ) {
759+ PyObject * newtype ;
760+ newtype = PyDict_GetItem (errnomap , myerrno );
761+ if (newtype ) {
762+ assert (PyType_Check (newtype ));
763+ type = (PyTypeObject * ) newtype ;
764+ }
765+ else if (PyErr_Occurred ())
766+ goto error ;
767+ }
768+ }
769+
770+ self = (PyOSErrorObject * ) type -> tp_alloc (type , 0 );
771+ if (!self )
772+ goto error ;
773+
774+ self -> dict = NULL ;
775+ self -> traceback = self -> cause = self -> context = NULL ;
776+ self -> written = -1 ;
777+
778+ if (!oserror_use_init (type )) {
779+ if (oserror_init (self , & args , myerrno , strerror , filename
780+ #ifdef MS_WINDOWS
781+ , winerror
782+ #endif
783+ ))
784+ goto error ;
785+ }
786+
715787 return (PyObject * ) self ;
716788
717789error :
@@ -721,10 +793,40 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
721793}
722794
723795static int
724- OSError_init (PySyntaxErrorObject * self , PyObject * args , PyObject * kwds )
796+ OSError_init (PyOSErrorObject * self , PyObject * args , PyObject * kwds )
725797{
726- /* Everything already done in OSError_new */
798+ PyObject * myerrno = NULL , * strerror = NULL , * filename = NULL ;
799+ #ifdef MS_WINDOWS
800+ PyObject * winerror = NULL ;
801+ #endif
802+
803+ if (!oserror_use_init (Py_TYPE (self )))
804+ /* Everything already done in OSError_new */
805+ return 0 ;
806+
807+ if (!_PyArg_NoKeywords (Py_TYPE (self )-> tp_name , kwds ))
808+ return -1 ;
809+
810+ Py_INCREF (args );
811+ if (oserror_parse_args (& args , & myerrno , & strerror , & filename
812+ #ifdef MS_WINDOWS
813+ , & winerror
814+ #endif
815+ ))
816+ goto error ;
817+
818+ if (oserror_init (self , & args , myerrno , strerror , filename
819+ #ifdef MS_WINDOWS
820+ , winerror
821+ #endif
822+ ))
823+ goto error ;
824+
727825 return 0 ;
826+
827+ error :
828+ Py_XDECREF (args );
829+ return -1 ;
728830}
729831
730832static int
0 commit comments