@@ -96,7 +96,7 @@ Status append(PyObject* elem, SequenceBuilder& builder,
9696 } else if (PyDict_Check (elem)) {
9797 builder.AppendDict (PyDict_Size (elem));
9898 subdicts.push_back (elem);
99- } else if (PyTuple_Check (elem)) {
99+ } else if (PyTuple_CheckExact (elem)) {
100100 builder.AppendTuple (PyTuple_Size (elem));
101101 subtuples.push_back (elem);
102102 } else if (PyArray_IsScalar (elem, Generic)) {
@@ -113,14 +113,15 @@ Status append(PyObject* elem, SequenceBuilder& builder,
113113 return Status::NotImplemented (ss.str ());
114114 } else {
115115 PyObject* arglist = Py_BuildValue (" (O)" , elem);
116+ // The reference count of the result of the call to PyObject_CallObject
117+ // must be decremented. This is done in SerializeDict in this file.
116118 PyObject* result = PyObject_CallObject (numbuf_serialize_callback, arglist);
119+ Py_XDECREF (arglist);
117120 if (!result) {
118- Py_XDECREF (arglist);
119121 return Status::NotImplemented (" python error" ); // TODO(pcm): https://github.com/pcmoritz/numbuf/issues/10
120122 }
121123 builder.AppendDict (PyDict_Size (result));
122124 subdicts.push_back (result);
123- Py_XDECREF (arglist);
124125 }
125126 }
126127 return Status::OK ();
@@ -219,6 +220,20 @@ Status SerializeDict(std::vector<PyObject*> dicts, std::shared_ptr<Array>* out)
219220 RETURN_NOT_OK (SerializeDict (val_dicts, &val_dict_arr));
220221 }
221222 *out = result.Finish (key_tuples_arr, val_list_arr, val_tuples_arr, val_dict_arr);
223+
224+ // This block is used to decrement the reference counts of the results
225+ // returned by the serialization callback, which is called in SerializeArray
226+ // in numpy.cc as well as in DeserializeDict and in append in this file.
227+ static PyObject* py_type = PyString_FromString (" _pytype_" );
228+ for (const auto & dict : dicts) {
229+ if (PyDict_Contains (dict, py_type)) {
230+ // If the dictionary contains the key "_pytype_", then the user has to
231+ // have registered a callback.
232+ ARROW_CHECK (numbuf_serialize_callback);
233+ Py_XDECREF (dict);
234+ }
235+ }
236+
222237 return Status::OK ();
223238}
224239
@@ -237,12 +252,15 @@ Status DeserializeDict(std::shared_ptr<Array> array, int32_t start_idx, int32_t
237252 static PyObject* py_type = PyString_FromString (" _pytype_" );
238253 if (PyDict_Contains (result, py_type) && numbuf_deserialize_callback) {
239254 PyObject* arglist = Py_BuildValue (" (O)" , result);
240- result = PyObject_CallObject (numbuf_deserialize_callback, arglist);
241- if (!result) {
242- Py_XDECREF (arglist);
255+ // The result of the call to PyObject_CallObject will be passed to Python
256+ // and its reference count will be decremented by the interpreter.
257+ PyObject* callback_result = PyObject_CallObject (numbuf_deserialize_callback, arglist);
258+ Py_XDECREF (arglist);
259+ Py_XDECREF (result);
260+ result = callback_result;
261+ if (!callback_result) {
243262 return Status::NotImplemented (" python error" ); // TODO(pcm): https://github.com/pcmoritz/numbuf/issues/10
244263 }
245- Py_XDECREF (arglist);
246264 }
247265 *out = result;
248266 return Status::OK ();
0 commit comments