Fix dtype string leak

`PyArray_DescrConverter_` doesn't steal a reference to the argument,
and so the passed arguments shouldn't be `.release()`d.
This commit is contained in:
Jason Rhinelander 2017-09-19 22:12:46 -03:00
parent 0aef6422a3
commit c6a57c10d1
3 changed files with 17 additions and 1 deletions

View File

@ -440,7 +440,7 @@ public:
/// This is essentially the same as calling numpy.dtype(args) in Python. /// This is essentially the same as calling numpy.dtype(args) in Python.
static dtype from_args(object args) { static dtype from_args(object args) {
PyObject *ptr = nullptr; PyObject *ptr = nullptr;
if (!detail::npy_api::get().PyArray_DescrConverter_(args.release().ptr(), &ptr) || !ptr) if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr)
throw error_already_set(); throw error_already_set();
return reinterpret_steal<dtype>(ptr); return reinterpret_steal<dtype>(ptr);
} }

View File

@ -448,4 +448,7 @@ TEST_SUBMODULE(numpy_dtypes, m) {
// test_register_dtype // test_register_dtype
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); }); m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
// test_str_leak
m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); });
} }

View File

@ -293,6 +293,19 @@ def test_register_dtype():
assert 'dtype is already registered' in str(excinfo.value) assert 'dtype is already registered' in str(excinfo.value)
@pytest.unsupported_on_pypy
def test_str_leak():
from sys import getrefcount
fmt = "f4"
pytest.gc_collect()
start = getrefcount(fmt)
d = m.dtype_wrapper(fmt)
assert d is np.dtype("f4")
del d
pytest.gc_collect()
assert getrefcount(fmt) == start
@pytest.requires_numpy @pytest.requires_numpy
def test_compare_buffer_info(): def test_compare_buffer_info():
assert all(m.compare_buffer_info()) assert all(m.compare_buffer_info())