@@ -13,39 +13,35 @@ static const Py_ssize_t MASK_LEN = 4;
1313/* Similar to PyBytes_AsStringAndSize, but accepts more types */
1414
1515static int
16- _PyBytesLike_AsStringAndSize (PyObject * obj , char * * buffer , Py_ssize_t * length )
16+ _PyBytesLike_AsStringAndSize (PyObject * obj , PyObject * * tmp , char * * buffer , Py_ssize_t * length )
1717{
18- // This supports bytes, bytearrays, and C-contiguous memoryview objects,
19- // which are the most useful data structures for handling byte streams.
20- // websockets.framing.prepare_data() returns only values of these types.
21- // Any object implementing the buffer protocol could be supported, however
22- // that would require allocation or copying memory, which is expensive.
18+ // This supports bytes, bytearrays, and memoryview objects,
19+ // which are common data structures for handling byte streams.
20+ // websockets.framing.prepare_data() returns only these types.
21+ // If *tmp isn't NULL, the caller gets a new reference.
2322 if (PyBytes_Check (obj ))
2423 {
24+ * tmp = NULL ;
2525 * buffer = PyBytes_AS_STRING (obj );
2626 * length = PyBytes_GET_SIZE (obj );
2727 }
2828 else if (PyByteArray_Check (obj ))
2929 {
30+ * tmp = NULL ;
3031 * buffer = PyByteArray_AS_STRING (obj );
3132 * length = PyByteArray_GET_SIZE (obj );
3233 }
3334 else if (PyMemoryView_Check (obj ))
3435 {
35- Py_buffer * mv_buf ;
36- mv_buf = PyMemoryView_GET_BUFFER (obj );
37- if (PyBuffer_IsContiguous (mv_buf , 'C' ))
38- {
39- * buffer = mv_buf -> buf ;
40- * length = mv_buf -> len ;
41- }
42- else
36+ * tmp = PyMemoryView_GetContiguous (obj , PyBUF_READ , 'C' );
37+ if (* tmp == NULL )
4338 {
44- PyErr_Format (
45- PyExc_TypeError ,
46- "expected a contiguous memoryview" );
4739 return -1 ;
4840 }
41+ Py_buffer * mv_buf ;
42+ mv_buf = PyMemoryView_GET_BUFFER (* tmp );
43+ * buffer = mv_buf -> buf ;
44+ * length = mv_buf -> len ;
4945 }
5046 else
5147 {
@@ -74,15 +70,17 @@ apply_mask(PyObject *self, PyObject *args, PyObject *kwds)
7470 // A pointer to a char * + length will be extracted from the data and mask
7571 // arguments, possibly via a Py_buffer.
7672
73+ PyObject * input_tmp = NULL ;
7774 char * input ;
7875 Py_ssize_t input_len ;
76+ PyObject * mask_tmp = NULL ;
7977 char * mask ;
8078 Py_ssize_t mask_len ;
8179
8280 // Initialize a PyBytesObject then get a pointer to the underlying char *
8381 // in order to avoid an extra memory copy in PyBytes_FromStringAndSize.
8482
85- PyObject * result ;
83+ PyObject * result = NULL ;
8684 char * output ;
8785
8886 // Other variables.
@@ -94,31 +92,31 @@ apply_mask(PyObject *self, PyObject *args, PyObject *kwds)
9492 if (!PyArg_ParseTupleAndKeywords (
9593 args , kwds , "OO" , kwlist , & input_obj , & mask_obj ))
9694 {
97- return NULL ;
95+ goto exit ;
9896 }
9997
100- if (_PyBytesLike_AsStringAndSize (input_obj , & input , & input_len ) == -1 )
98+ if (_PyBytesLike_AsStringAndSize (input_obj , & input_tmp , & input , & input_len ) == -1 )
10199 {
102- return NULL ;
100+ goto exit ;
103101 }
104102
105- if (_PyBytesLike_AsStringAndSize (mask_obj , & mask , & mask_len ) == -1 )
103+ if (_PyBytesLike_AsStringAndSize (mask_obj , & mask_tmp , & mask , & mask_len ) == -1 )
106104 {
107- return NULL ;
105+ goto exit ;
108106 }
109107
110108 if (mask_len != MASK_LEN )
111109 {
112110 PyErr_SetString (PyExc_ValueError , "mask must contain 4 bytes" );
113- return NULL ;
111+ goto exit ;
114112 }
115113
116114 // Create output.
117115
118116 result = PyBytes_FromStringAndSize (NULL , input_len );
119117 if (result == NULL )
120118 {
121- return NULL ;
119+ goto exit ;
122120 }
123121
124122 // Since we juste created result, we don't need error checks.
@@ -172,6 +170,9 @@ apply_mask(PyObject *self, PyObject *args, PyObject *kwds)
172170 output [i ] = input [i ] ^ mask [i & (MASK_LEN - 1 )];
173171 }
174172
173+ exit :
174+ Py_XDECREF (input_tmp );
175+ Py_XDECREF (mask_tmp );
175176 return result ;
176177
177178}
0 commit comments