Skip to content

Commit 5ac2df4

Browse files
robertnishiharapcmoritz
authored andcommitted
Don't increment reference count in Py_BuildValue. (#12)
* Decrement reference count for result of serialization callback and also for an object created in DeserializeDict. * Check tuples exactly so named tuples go to callback. * Assert that callback is set if _pytype_ key present.
1 parent 2e4b655 commit 5ac2df4

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

python/src/pynumbuf/adapters/numpy.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,15 @@ Status SerializeArray(PyArrayObject* array, SequenceBuilder& builder,
114114
return Status::NotImplemented(stream.str());
115115
} else {
116116
PyObject* arglist = Py_BuildValue("(O)", array);
117+
// The reference count of the result of the call to PyObject_CallObject
118+
// must be decremented. This is done in SerializeDict in python.cc.
117119
PyObject* result = PyObject_CallObject(numbuf_serialize_callback, arglist);
120+
Py_XDECREF(arglist);
118121
if (!result) {
119-
Py_XDECREF(arglist);
120122
return Status::NotImplemented("python error"); // TODO(pcm): https://github.com/pcmoritz/numbuf/issues/10
121123
}
122124
builder.AppendDict(PyDict_Size(result));
123125
subdicts.push_back(result);
124-
Py_XDECREF(arglist);
125126
}
126127
}
127128
Py_XDECREF(contiguous);

python/src/pynumbuf/adapters/python.cc

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)