From ba0b92eecb474790d84c424f15861797dd25e507 Mon Sep 17 00:00:00 2001 From: Aviram Hassan <aviramyhassan@gmail.com> Date: Thu, 13 Jan 2022 19:08:18 +0200 Subject: [PATCH] Fix conversion of non-mapping sequences into `PyMapping` (i.e `PyStr` can be cast to `PyMapping`) due to `PyMapping_Check` returning true for sequences. --- CHANGELOG.md | 1 + src/types/mapping.rs | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eba57ef4bb7..4f807e84099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix undefined behavior in `PySlice::indices`. [#2061](https://github.com/PyO3/pyo3/pull/2061) - Use the Rust function path for `wrap_pymodule!` of a `#[pymodule]` with a `#[pyo3(name = "..")]` attribute, not the Python name. [#2081](https://github.com/PyO3/pyo3/pull/2081) - Fix panic in `#[pyfunction]` generated code when a required argument following an `Option` was not provided. [#2093](https://github.com/PyO3/pyo3/pull/2093) +- Fix conversion of non-mapping sequences into `PyMapping` (i.e `PyStr` can be cast to `PyMapping`) due to `PyMapping_Check` returning true for sequences. [#2098](https://github.com/PyO3/pyo3/pull/2098) ## [0.15.1] - 2021-11-19 diff --git a/src/types/mapping.rs b/src/types/mapping.rs index 0ff430a004c..cf71ac8c1af 100644 --- a/src/types/mapping.rs +++ b/src/types/mapping.rs @@ -101,7 +101,9 @@ impl<'v> PyTryFrom<'v> for PyMapping { fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyMapping, PyDowncastError<'v>> { let value = value.into(); unsafe { - if ffi::PyMapping_Check(value.as_ptr()) != 0 { + if ffi::PyMapping_Check(value.as_ptr()) != 0 + && ffi::PySequence_Check(value.as_ptr()) == 0 + { Ok(<PyMapping as PyTryFrom>::try_from_unchecked(value)) } else { Err(PyDowncastError::new(value, "Mapping")) @@ -142,8 +144,8 @@ mod tests { use std::collections::HashMap; use crate::{ - exceptions::PyKeyError, - types::{PyDict, PyTuple}, + exceptions::{PyKeyError, PyTypeError}, + types::{PyDict, PyString, PyTuple}, Python, }; @@ -299,4 +301,12 @@ mod tests { assert_eq!(mapping_ref.get_refcnt(), 2); }) } + + #[test] + fn test_not_mapping() { + Python::with_gil(|py| { + let str = PyString::new(py, "hello, world"); + str.downcast::<PyMapping>().unwrap_err(); + }); + } }