diff --git a/examples/rustapi_module/requirements-dev.txt b/examples/rustapi_module/requirements-dev.txt index 1aad0c65..b3b34d9d 100644 --- a/examples/rustapi_module/requirements-dev.txt +++ b/examples/rustapi_module/requirements-dev.txt @@ -2,3 +2,4 @@ pip>=19.1 hypothesis>=3.55 pytest>=3.5.0 setuptools-rust>=0.10.2 +psutil>=5.6 diff --git a/examples/rustapi_module/setup.py b/examples/rustapi_module/setup.py index 2a277457..3f84a32a 100644 --- a/examples/rustapi_module/setup.py +++ b/examples/rustapi_module/setup.py @@ -97,6 +97,7 @@ setup( make_rust_extension("rustapi_module.datetime"), make_rust_extension("rustapi_module.subclassing"), make_rust_extension("rustapi_module.test_dict"), + make_rust_extension("rustapi_module.buf_and_str"), ], install_requires=install_requires, tests_require=tests_require, diff --git a/examples/rustapi_module/src/buf_and_str.rs b/examples/rustapi_module/src/buf_and_str.rs new file mode 100644 index 00000000..5f068d43 --- /dev/null +++ b/examples/rustapi_module/src/buf_and_str.rs @@ -0,0 +1,31 @@ +//! Objects related to PyBuffer and PyStr +use pyo3::prelude::*; +use pyo3::types::{PyBytes, PyString}; + +/// This is for confirming that PyBuffer does not cause memory leak +#[pyclass] +struct BytesExtractor {} + +#[pymethods] +impl BytesExtractor { + #[new] + pub fn __new__(obj: &PyRawObject) { + obj.init({ BytesExtractor {} }); + } + + pub fn to_vec(&mut self, bytes: &PyBytes) -> PyResult { + let byte_vec: Vec = bytes.extract().unwrap(); + Ok(byte_vec.len()) + } + + pub fn to_str(&mut self, bytes: &PyString) -> PyResult { + let byte_str: String = bytes.extract().unwrap(); + Ok(byte_str.len()) + } +} + +#[pymodule] +pub fn buf_and_str(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) +} diff --git a/examples/rustapi_module/src/lib.rs b/examples/rustapi_module/src/lib.rs index be7fd6ed..0f5895a8 100644 --- a/examples/rustapi_module/src/lib.rs +++ b/examples/rustapi_module/src/lib.rs @@ -1,3 +1,4 @@ +pub mod buf_and_str; pub mod datetime; pub mod dict_iter; pub mod othermod; diff --git a/examples/rustapi_module/tests/test_buf_and_str.py b/examples/rustapi_module/tests/test_buf_and_str.py new file mode 100644 index 00000000..94538865 --- /dev/null +++ b/examples/rustapi_module/tests/test_buf_and_str.py @@ -0,0 +1,38 @@ +import os +import platform +import psutil +import pytest +from rustapi_module.buf_and_str import BytesExtractor + +PYPY = platform.python_implementation() == "PyPy" + + +@pytest.mark.skipif( + PYPY, + reason="PyPy has a segfault bug around this area." + "See https://github.com/PyO3/pyo3/issues/589 for detail.", +) +def test_pybuffer_doesnot_leak_memory(): + N = 1000 + extractor = BytesExtractor() + process = psutil.Process(os.getpid()) + + def memory_diff(f): + before = process.memory_info().rss + f() + after = process.memory_info().rss + return after - before + + message_b = b'\\(-"-;) Praying that memory leak would not happen..' + message_s = '\\(-"-;) Praying that memory leak would not happen..' + + def to_vec(): + for i in range(N): + extractor.to_vec(message_b) + + def to_str(): + for i in range(N): + extractor.to_str(message_s) + + memory_diff(to_vec) == 0 + memory_diff(to_str) == 0 diff --git a/src/buffer.rs b/src/buffer.rs index a3eca6c2..91c317f6 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -582,7 +582,6 @@ impl PyBuffer { let ptr = &*self.0 as *const ffi::Py_buffer as *mut ffi::Py_buffer; ffi::PyBuffer_Release(ptr) }; - mem::forget(self); } } diff --git a/tests/ui/reject_generics.stderr b/tests/ui/reject_generics.stderr index 7084138e..c06f9dfb 100644 --- a/tests/ui/reject_generics.stderr +++ b/tests/ui/reject_generics.stderr @@ -3,5 +3,3 @@ error: #[pyclass] cannot have generic parameters | 4 | struct ClassWithGenerics { | ^^^ - -error: Could not compile `pyo3-tests`. diff --git a/tests/ui/too_many_args_to_getter.stderr b/tests/ui/too_many_args_to_getter.stderr index 341b278e..a81bb1be 100644 --- a/tests/ui/too_many_args_to_getter.stderr +++ b/tests/ui/too_many_args_to_getter.stderr @@ -3,5 +3,3 @@ error: Getter function can only have one argument of type pyo3::Python! | 11 | fn get_num(&self, index: u32) {} | ^^^ - -error: Could not compile `pyo3-tests`.