@@ -76,41 +76,60 @@ is_running_main(PyInterpreterState *interp)
7676// XXX Release when the original interpreter is destroyed.
7777
7878typedef struct {
79- PyObject_HEAD
79+ PyObject base ;
8080 Py_buffer * view ;
8181 int64_t interpid ;
8282} XIBufferViewObject ;
8383
8484#define XIBufferViewObject_CAST (op ) ((XIBufferViewObject *)(op))
8585
8686static PyObject *
87- xibufferview_from_xid (PyTypeObject * cls , _PyXIData_t * data )
87+ xibufferview_from_buffer (PyTypeObject * cls , Py_buffer * view , int64_t interpid )
8888{
89- assert (_PyXIData_DATA (data ) != NULL );
90- assert (_PyXIData_OBJ (data ) == NULL );
91- assert (_PyXIData_INTERPID (data ) >= 0 );
89+ assert (interpid >= 0 );
90+
91+ Py_buffer * copied = PyMem_RawMalloc (sizeof (Py_buffer ));
92+ if (copied == NULL ) {
93+ return NULL ;
94+ }
95+ /* This steals the view->obj reference */
96+ * copied = * view ;
97+
9298 XIBufferViewObject * self = PyObject_Malloc (sizeof (XIBufferViewObject ));
9399 if (self == NULL ) {
100+ PyMem_RawFree (copied );
94101 return NULL ;
95102 }
96- PyObject_Init ((PyObject * )self , cls );
97- self -> view = (Py_buffer * )_PyXIData_DATA (data );
98- self -> interpid = _PyXIData_INTERPID (data );
103+ PyObject_Init (& self -> base , cls );
104+ * self = (XIBufferViewObject ){
105+ .base = self -> base ,
106+ .view = copied ,
107+ .interpid = interpid ,
108+ };
99109 return (PyObject * )self ;
100110}
101111
102112static void
103113xibufferview_dealloc (PyObject * op )
104114{
105115 XIBufferViewObject * self = XIBufferViewObject_CAST (op );
106- PyInterpreterState * interp = _PyInterpreterState_LookUpID (self -> interpid );
107- /* If the interpreter is no longer alive then we have problems,
108- since other objects may be using the buffer still. */
109- assert (interp != NULL );
110116
111- if (_PyBuffer_ReleaseInInterpreterAndRawFree (interp , self -> view ) < 0 ) {
112- // XXX Emit a warning?
113- PyErr_Clear ();
117+ if (self -> view != NULL ) {
118+ PyInterpreterState * interp =
119+ _PyInterpreterState_LookUpID (self -> interpid );
120+ if (interp == NULL ) {
121+ /* The interpreter is no longer alive. */
122+ PyErr_Clear ();
123+ PyMem_RawFree (self -> view );
124+ }
125+ else {
126+ if (_PyBuffer_ReleaseInInterpreterAndRawFree (interp ,
127+ self -> view ) < 0 )
128+ {
129+ // XXX Emit a warning?
130+ PyErr_Clear ();
131+ }
132+ }
114133 }
115134
116135 PyTypeObject * tp = Py_TYPE (self );
@@ -155,32 +174,64 @@ static PyType_Spec XIBufferViewType_spec = {
155174
156175static PyTypeObject * _get_current_xibufferview_type (void );
157176
177+
178+ struct xibuffer {
179+ Py_buffer view ;
180+ int used ;
181+ };
182+
158183static PyObject *
159184_memoryview_from_xid (_PyXIData_t * data )
160185{
186+ assert (_PyXIData_DATA (data ) != NULL );
187+ assert (_PyXIData_OBJ (data ) == NULL );
188+ assert (_PyXIData_INTERPID (data ) >= 0 );
189+ struct xibuffer * view = (struct xibuffer * )_PyXIData_DATA (data );
190+ assert (!view -> used );
191+
161192 PyTypeObject * cls = _get_current_xibufferview_type ();
162193 if (cls == NULL ) {
163194 return NULL ;
164195 }
165- PyObject * obj = xibufferview_from_xid (cls , data );
196+
197+ PyObject * obj = xibufferview_from_buffer (
198+ cls , & view -> view , _PyXIData_INTERPID (data ));
166199 if (obj == NULL ) {
167200 return NULL ;
168201 }
169- return PyMemoryView_FromObject (obj );
202+ PyObject * res = PyMemoryView_FromObject (obj );
203+ if (res == NULL ) {
204+ Py_DECREF (obj );
205+ return NULL ;
206+ }
207+ view -> used = 1 ;
208+ return res ;
209+ }
210+
211+ static void
212+ _pybuffer_shared_free (void * data )
213+ {
214+ struct xibuffer * view = (struct xibuffer * )data ;
215+ if (!view -> used ) {
216+ PyBuffer_Release (& view -> view );
217+ }
218+ PyMem_RawFree (data );
170219}
171220
172221static int
173- _memoryview_shared (PyThreadState * tstate , PyObject * obj , _PyXIData_t * data )
222+ _pybuffer_shared (PyThreadState * tstate , PyObject * obj , _PyXIData_t * data )
174223{
175- Py_buffer * view = PyMem_RawMalloc (sizeof (Py_buffer ));
224+ struct xibuffer * view = PyMem_RawMalloc (sizeof (struct xibuffer ));
176225 if (view == NULL ) {
177226 return -1 ;
178227 }
179- if (PyObject_GetBuffer (obj , view , PyBUF_FULL_RO ) < 0 ) {
228+ view -> used = 0 ;
229+ if (PyObject_GetBuffer (obj , & view -> view , PyBUF_FULL_RO ) < 0 ) {
180230 PyMem_RawFree (view );
181231 return -1 ;
182232 }
183233 _PyXIData_Init (data , tstate -> interp , view , NULL , _memoryview_from_xid );
234+ data -> free = _pybuffer_shared_free ;
184235 return 0 ;
185236}
186237
@@ -201,7 +252,7 @@ register_memoryview_xid(PyObject *mod, PyTypeObject **p_state)
201252 * p_state = cls ;
202253
203254 // Register XID for the builtin memoryview type.
204- if (ensure_xid_class (& PyMemoryView_Type , _memoryview_shared ) < 0 ) {
255+ if (ensure_xid_class (& PyMemoryView_Type , _pybuffer_shared ) < 0 ) {
205256 return -1 ;
206257 }
207258 // We don't ever bother un-registering memoryview.
0 commit comments