@@ -70,6 +70,7 @@ typedef struct {
7070 formatcode * s_codes ;
7171 PyObject * s_format ;
7272 PyObject * weakreflist ; /* List of weak references */
73+ PyMutex mutex ; /* to prevent mutation during packing */
7374} PyStructObject ;
7475
7576#define PyStructObject_CAST (op ) ((PyStructObject *)(op))
@@ -1773,6 +1774,7 @@ s_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
17731774 s -> s_codes = NULL ;
17741775 s -> s_size = -1 ;
17751776 s -> s_len = -1 ;
1777+ s -> mutex = (PyMutex ){0 };
17761778 }
17771779 return self ;
17781780}
@@ -1816,6 +1818,11 @@ Struct___init___impl(PyStructObject *self, PyObject *format)
18161818
18171819 Py_SETREF (self -> s_format , format );
18181820
1821+ if (PyMutex_IsLocked (& self -> mutex )) {
1822+ PyErr_SetString (PyExc_RuntimeError ,
1823+ "Call Struct.__init__() in struct.pack()" );
1824+ return -1 ;
1825+ }
18191826 ret = prepare_s (self );
18201827 return ret ;
18211828}
@@ -2146,24 +2153,14 @@ static int
21462153s_pack_internal (PyStructObject * soself , PyObject * const * args , int offset ,
21472154 char * buf , _structmodulestate * state )
21482155{
2149- formatcode * code , * frozen_codes ;
2156+ formatcode * code ;
21502157 /* XXX(nnorwitz): why does i need to be a local? can we use
21512158 the offset parameter or do we need the wider width? */
2152- Py_ssize_t i , frozen_size = 1 ;
2159+ Py_ssize_t i ;
21532160
2154- /* Take copy of soself->s_codes, as dunder methods of arguments (e.g.
2155- __bool__ of __float__) could modify the struct object during packing. */
2156- for (code = soself -> s_codes ; code -> fmtdef != NULL ; code ++ ) {
2157- frozen_size ++ ;
2158- }
2159- frozen_codes = PyMem_Malloc (frozen_size * sizeof (formatcode ));
2160- if (!frozen_codes ) {
2161- goto err ;
2162- }
2163- memcpy (frozen_codes , soself -> s_codes , frozen_size * sizeof (formatcode ));
21642161 memset (buf , '\0' , soself -> s_size );
21652162 i = offset ;
2166- for (code = frozen_codes ; code -> fmtdef != NULL ; code ++ ) {
2163+ for (code = soself -> s_codes ; code -> fmtdef != NULL ; code ++ ) {
21672164 const formatdef * e = code -> fmtdef ;
21682165 char * res = buf + code -> offset ;
21692166 Py_ssize_t j = code -> repeat ;
@@ -2177,7 +2174,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset,
21772174 if (!isstring && !PyByteArray_Check (v )) {
21782175 PyErr_SetString (state -> StructError ,
21792176 "argument for 's' must be a bytes object" );
2180- goto err ;
2177+ return -1 ;
21812178 }
21822179 if (isstring ) {
21832180 n = PyBytes_GET_SIZE (v );
@@ -2199,7 +2196,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset,
21992196 if (!isstring && !PyByteArray_Check (v )) {
22002197 PyErr_SetString (state -> StructError ,
22012198 "argument for 'p' must be a bytes object" );
2202- goto err ;
2199+ return -1 ;
22032200 }
22042201 if (isstring ) {
22052202 n = PyBytes_GET_SIZE (v );
@@ -2225,20 +2222,15 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset,
22252222 if (PyLong_Check (v ) && PyErr_ExceptionMatches (PyExc_OverflowError ))
22262223 PyErr_SetString (state -> StructError ,
22272224 "int too large to convert" );
2228- goto err ;
2225+ return -1 ;
22292226 }
22302227 }
22312228 res += code -> size ;
22322229 }
22332230 }
22342231
22352232 /* Success */
2236- PyMem_Free (frozen_codes );
22372233 return 0 ;
2238- err :
2239- /* Failure */
2240- PyMem_Free (frozen_codes );
2241- return -1 ;
22422234}
22432235
22442236
@@ -2272,17 +2264,22 @@ s_pack(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
22722264 return NULL ;
22732265 }
22742266 char * buf = PyBytesWriter_GetData (writer );
2275- /* Take copy of soself->s_size, as dunder methods of arguments (e.g.
2276- __bool__ of __float__) could modify the struct object during packing. */
2277- Py_ssize_t frozen_size = soself -> s_size ;
22782267
22792268 /* Call the guts */
2269+ if (PyMutex_IsLocked (& soself -> mutex )) {
2270+ PyErr_SetString (PyExc_RuntimeError , "XXX" );
2271+ PyBytesWriter_Discard (writer );
2272+ return NULL ;
2273+ }
2274+ PyMutex_Lock (& soself -> mutex );
22802275 if ( s_pack_internal (soself , args , 0 , buf , state ) != 0 ) {
2276+ PyMutex_Unlock (& soself -> mutex );
22812277 PyBytesWriter_Discard (writer );
22822278 return NULL ;
22832279 }
2280+ PyMutex_Unlock (& soself -> mutex );
22842281
2285- return PyBytesWriter_FinishWithSize (writer , frozen_size );
2282+ return PyBytesWriter_FinishWithSize (writer , soself -> s_size );
22862283}
22872284
22882285PyDoc_STRVAR (s_pack_into__doc__ ,
@@ -2378,11 +2375,13 @@ s_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
23782375 }
23792376
23802377 /* Call the guts */
2378+ PyMutex_Lock (& soself -> mutex );
23812379 if (s_pack_internal (soself , args , 2 , (char * )buffer .buf + offset , state ) != 0 ) {
2380+ PyMutex_Unlock (& soself -> mutex );
23822381 PyBuffer_Release (& buffer );
23832382 return NULL ;
23842383 }
2385-
2384+ PyMutex_Unlock ( & soself -> mutex );
23862385 PyBuffer_Release (& buffer );
23872386 Py_RETURN_NONE ;
23882387}
0 commit comments