Fix PyDictIterator's segfault(for #159)

This commit is contained in:
kngwyu 2018-11-13 00:24:59 +09:00
parent cd23574d8a
commit 34099b33f8
5 changed files with 71 additions and 5 deletions

View file

@ -60,6 +60,11 @@ setup(
"Cargo.toml", "Cargo.toml",
rustc_flags=get_py_version_cfgs(), rustc_flags=get_py_version_cfgs(),
), ),
RustExtension(
"rustapi_module._test_dict",
"Cargo.toml",
rustc_flags=get_py_version_cfgs(),
),
], ],
install_requires=install_requires, install_requires=install_requires,
tests_require=tests_require, tests_require=tests_require,

View file

@ -0,0 +1,42 @@
use pyo3::prelude::*;
use pyo3::exceptions as exc;
use pyo3::types::PyDict;
#[pymodinit(_test_dict)]
fn test_dict(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<DictSize>()?;
Ok(())
}
#[pyclass]
pub struct DictSize {
expected: u32,
}
#[pymethods]
impl DictSize {
#[new]
fn __new__(obj: &PyRawObject, expected: u32) -> PyResult<()> {
obj.init(|_t| DictSize { expected })
}
fn iter_dict(&mut self, _py: Python, dict: &PyDict) -> PyResult<u32> {
let mut seen = 0u32;
for (sym, values) in dict.iter() {
seen += 1;
println!(
"{:4}/{:4} iterations:{}=>{}",
seen, self.expected, sym, values
);
}
match seen == self.expected {
true => Ok(seen),
_ => Err(PyErr::new::<exc::TypeError, _>(format!(
"Expected {} iterations - performed {}",
self.expected, seen
))),
}
}
}

View file

@ -4,5 +4,6 @@
extern crate pyo3; extern crate pyo3;
pub mod datetime; pub mod datetime;
pub mod dict_iter;
pub mod othermod; pub mod othermod;
pub mod subclassing; pub mod subclassing;

View file

@ -0,0 +1,12 @@
from rustapi_module._test_dict import DictSize
import pytest
@pytest.mark.parametrize(
"size",
[64, 128, 256],
)
def test_size(size):
d = {}
for i in range(0,size):
d[i] = str(i)
assert DictSize(len(d)).iter_dict(d) == size

View file

@ -8,7 +8,7 @@ use crate::object::PyObject;
use crate::python::{IntoPyPointer, Python, ToPyPointer}; use crate::python::{IntoPyPointer, Python, ToPyPointer};
use crate::types::{PyList, PyObjectRef}; use crate::types::{PyList, PyObjectRef};
use std; use std;
use std::{cmp, collections, hash, mem}; use std::{cmp, collections, hash, marker::PhantomData, mem};
/// Represents a Python `dict`. /// Represents a Python `dict`.
#[repr(transparent)] #[repr(transparent)]
@ -148,13 +148,19 @@ impl PyDict {
/// Note that it's unsafe to use when the dictionary might be changed /// Note that it's unsafe to use when the dictionary might be changed
/// by other python code. /// by other python code.
pub fn iter(&self) -> PyDictIterator { pub fn iter(&self) -> PyDictIterator {
PyDictIterator { dict: self, pos: 0 } let py = self.py();
PyDictIterator {
dict: self.to_object(py),
pos: 0,
__marker: PhantomData,
}
} }
} }
pub struct PyDictIterator<'a> { pub struct PyDictIterator<'dict> {
dict: &'a PyDict, dict: PyObject,
pos: isize, pos: isize,
__marker: PhantomData<&'dict ()>,
} }
impl<'a> Iterator for PyDictIterator<'a> { impl<'a> Iterator for PyDictIterator<'a> {
@ -166,7 +172,7 @@ impl<'a> Iterator for PyDictIterator<'a> {
let mut key: *mut ffi::PyObject = mem::uninitialized(); let mut key: *mut ffi::PyObject = mem::uninitialized();
let mut value: *mut ffi::PyObject = mem::uninitialized(); let mut value: *mut ffi::PyObject = mem::uninitialized();
if ffi::PyDict_Next(self.dict.as_ptr(), &mut self.pos, &mut key, &mut value) != 0 { if ffi::PyDict_Next(self.dict.as_ptr(), &mut self.pos, &mut key, &mut value) != 0 {
let py = self.dict.py(); let py = Python::assume_gil_acquired();
Some((py.from_borrowed_ptr(key), py.from_borrowed_ptr(value))) Some((py.from_borrowed_ptr(key), py.from_borrowed_ptr(value)))
} else { } else {
None None