@@ -77,6 +77,11 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
7777 return (PyObject * )self ;
7878}
7979
80+ static inline void BaseException_init_timestamp (PyBaseExceptionObject * self )
81+ {
82+ PyTime_TimeRaw (& self -> timestamp_ns ); /* fills in 0 on failure. */
83+ }
84+
8085static int
8186BaseException_init (PyBaseExceptionObject * self , PyObject * args , PyObject * kwds )
8287{
@@ -88,7 +93,7 @@ BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
8893 Py_IS_TYPE (self , (PyTypeObject * )PyExc_StopAsyncIteration )) {
8994 self -> timestamp_ns = 0 ; /* fast; frequent non-error control flow. */
9095 } else {
91- PyTime_TimeRaw ( & self -> timestamp_ns ); /* fills in 0 on failure. */
96+ BaseException_init_timestamp ( self );
9297 }
9398 return 0 ;
9499}
@@ -112,7 +117,7 @@ BaseException_vectorcall(PyObject *type_obj, PyObject * const*args,
112117 // The dict is created on the fly in PyObject_GenericSetAttr()
113118 self -> dict = NULL ;
114119 self -> notes = NULL ;
115- PyTime_TimeRaw ( & self -> timestamp_ns ); /* fills in 0 on failure. */
120+ BaseException_init_timestamp ( self );
116121 self -> traceback = NULL ;
117122 self -> cause = NULL ;
118123 self -> context = NULL ;
@@ -204,6 +209,23 @@ BaseException_repr(PyBaseExceptionObject *self)
204209
205210/* Pickling support */
206211
212+ /* Returns dict on success, after having added a __timestamp_ns__ key; NULL
213+ otherwise. dict does not have to be self->dict as the getstate use case
214+ often uses a copy. */
215+ static PyObject * BaseException_add_timestamp_to_dict (PyBaseExceptionObject * self , PyObject * dict )
216+ {
217+ assert (dict != NULL );
218+ PyObject * ts = PyLong_FromLongLong (self -> timestamp_ns );
219+ if (!ts )
220+ return NULL ;
221+ if (PyDict_SetItemString (dict , "__timestamp_ns__" , ts ) == -1 ) {
222+ Py_DECREF (ts );
223+ return NULL ;
224+ }
225+ Py_DECREF (ts );
226+ return dict ;
227+ }
228+
207229/*[clinic input]
208230@critical_section
209231BaseException.__reduce__
@@ -215,16 +237,14 @@ BaseException___reduce___impl(PyBaseExceptionObject *self)
215237{
216238 if (!self -> dict ) {
217239 self -> dict = PyDict_New ();
218- }
219- if (self -> args && self -> dict ) {
220- PyObject * ts = PyLong_FromLongLong (self -> timestamp_ns );
221- if (!ts )
222- return NULL ;
223- if (PyDict_SetItemString (self -> dict , "__timestamp_ns__" , ts ) == -1 ) {
224- Py_DECREF (ts );
240+ if (self -> dict == NULL ) {
225241 return NULL ;
226242 }
227- Py_DECREF (ts );
243+ }
244+ if (!BaseException_add_timestamp_to_dict (self , self -> dict )) {
245+ return NULL ;
246+ }
247+ if (self -> args && self -> dict ) {
228248 return PyTuple_Pack (3 , Py_TYPE (self ), self -> args , self -> dict );
229249 } else {
230250 return PyTuple_Pack (2 , Py_TYPE (self ), self -> args );
@@ -1804,30 +1824,26 @@ static PyObject *
18041824ImportError_getstate (PyImportErrorObject * self )
18051825{
18061826 PyObject * dict = ((PyBaseExceptionObject * )self )-> dict ;
1807- if (self -> name || self -> path || self -> name_from ) {
1808- dict = dict ? PyDict_Copy (dict ) : PyDict_New ();
1809- if (dict == NULL )
1810- return NULL ;
1811- if (self -> name && PyDict_SetItem (dict , & _Py_ID (name ), self -> name ) < 0 ) {
1812- Py_DECREF (dict );
1813- return NULL ;
1814- }
1815- if (self -> path && PyDict_SetItem (dict , & _Py_ID (path ), self -> path ) < 0 ) {
1816- Py_DECREF (dict );
1817- return NULL ;
1818- }
1819- if (self -> name_from && PyDict_SetItem (dict , & _Py_ID (name_from ), self -> name_from ) < 0 ) {
1820- Py_DECREF (dict );
1821- return NULL ;
1822- }
1823- return dict ;
1827+ dict = dict ? PyDict_Copy (dict ) : PyDict_New ();
1828+ if (dict == NULL ) {
1829+ return NULL ;
18241830 }
1825- else if (dict ) {
1826- return Py_NewRef ( dict ) ;
1831+ if (! BaseException_add_timestamp_to_dict (( PyBaseExceptionObject * ) self , dict ) ) {
1832+ return NULL ;
18271833 }
1828- else {
1829- Py_RETURN_NONE ;
1834+ if (self -> name && PyDict_SetItem (dict , & _Py_ID (name ), self -> name ) < 0 ) {
1835+ Py_DECREF (dict );
1836+ return NULL ;
1837+ }
1838+ if (self -> path && PyDict_SetItem (dict , & _Py_ID (path ), self -> path ) < 0 ) {
1839+ Py_DECREF (dict );
1840+ return NULL ;
18301841 }
1842+ if (self -> name_from && PyDict_SetItem (dict , & _Py_ID (name_from ), self -> name_from ) < 0 ) {
1843+ Py_DECREF (dict );
1844+ return NULL ;
1845+ }
1846+ return dict ;
18311847}
18321848
18331849/* Pickling support */
@@ -1840,10 +1856,8 @@ ImportError_reduce(PyImportErrorObject *self, PyObject *Py_UNUSED(ignored))
18401856 if (state == NULL )
18411857 return NULL ;
18421858 args = ((PyBaseExceptionObject * )self )-> args ;
1843- if (state == Py_None )
1844- res = PyTuple_Pack (2 , Py_TYPE (self ), args );
1845- else
1846- res = PyTuple_Pack (3 , Py_TYPE (self ), args , state );
1859+ assert (state != Py_None );
1860+ res = PyTuple_Pack (3 , Py_TYPE (self ), args , state );
18471861 Py_DECREF (state );
18481862 return res ;
18491863}
@@ -2119,6 +2133,8 @@ OSError_init(PyOSErrorObject *self, PyObject *args, PyObject *kwds)
21192133 PyObject * winerror = NULL ;
21202134#endif
21212135
2136+ BaseException_init_timestamp ((PyBaseExceptionObject * )self );
2137+
21222138 if (!oserror_use_init (Py_TYPE (self )))
21232139 /* Everything already done in OSError_new */
21242140 return 0 ;
@@ -2260,10 +2276,16 @@ OSError_reduce(PyOSErrorObject *self, PyObject *Py_UNUSED(ignored))
22602276 } else
22612277 Py_INCREF (args );
22622278
2263- if (self -> dict )
2264- res = PyTuple_Pack (3 , Py_TYPE (self ), args , self -> dict );
2265- else
2266- res = PyTuple_Pack (2 , Py_TYPE (self ), args );
2279+ if (!self -> dict ) {
2280+ self -> dict = PyDict_New ();
2281+ if (!self -> dict ) {
2282+ return NULL ;
2283+ }
2284+ }
2285+ if (!BaseException_add_timestamp_to_dict ((PyBaseExceptionObject * )self , self -> dict )) {
2286+ return NULL ;
2287+ }
2288+ res = PyTuple_Pack (3 , Py_TYPE (self ), args , self -> dict );
22672289 Py_DECREF (args );
22682290 return res ;
22692291}
@@ -2528,29 +2550,26 @@ AttributeError_traverse(PyAttributeErrorObject *self, visitproc visit, void *arg
25282550static PyObject *
25292551AttributeError_getstate (PyAttributeErrorObject * self , PyObject * Py_UNUSED (ignored ))
25302552{
2531- PyObject * dict = ((PyAttributeErrorObject * )self )-> dict ;
2532- if (self -> name || self -> args ) {
2533- dict = dict ? PyDict_Copy (dict ) : PyDict_New ();
2534- if (dict == NULL ) {
2535- return NULL ;
2536- }
2537- if (self -> name && PyDict_SetItemString (dict , "name" , self -> name ) < 0 ) {
2538- Py_DECREF (dict );
2539- return NULL ;
2540- }
2541- /* We specifically are not pickling the obj attribute since there are many
2542- cases where it is unlikely to be picklable. See GH-103352.
2543- */
2544- if (self -> args && PyDict_SetItemString (dict , "args" , self -> args ) < 0 ) {
2545- Py_DECREF (dict );
2546- return NULL ;
2547- }
2548- return dict ;
2553+ PyObject * dict = self -> dict ;
2554+ dict = dict ? PyDict_Copy (dict ) : PyDict_New ();
2555+ if (dict == NULL ) {
2556+ return NULL ;
25492557 }
2550- else if (dict ) {
2551- return Py_NewRef ( dict ) ;
2558+ if (! BaseException_add_timestamp_to_dict (( PyBaseExceptionObject * ) self , dict ) ) {
2559+ return NULL ;
25522560 }
2553- Py_RETURN_NONE ;
2561+ if (self -> name && PyDict_SetItemString (dict , "name" , self -> name ) < 0 ) {
2562+ Py_DECREF (dict );
2563+ return NULL ;
2564+ }
2565+ /* We specifically are not pickling the obj attribute since there are many
2566+ cases where it is unlikely to be picklable. See GH-103352.
2567+ */
2568+ if (self -> args && PyDict_SetItemString (dict , "args" , self -> args ) < 0 ) {
2569+ Py_DECREF (dict );
2570+ return NULL ;
2571+ }
2572+ return dict ;
25542573}
25552574
25562575static PyObject *
0 commit comments