Skip to content

Commit 5caaa37

Browse files
authored
fix: convert to cstrings in PyString::from_object (#5008)
fixes #5005 This only fixes the API, and adds a test of the API, it does not deprecate the API or introduce a version which takes `&CStr` directly, this can be done later.
1 parent 4aca459 commit 5caaa37

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

newsfragments/5008.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix `PyString::from_object`, avoid out of bounds reads by null terminating the `encoding` and `errors` parameters

src/types/string.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::types::PyBytes;
1010
use crate::IntoPy;
1111
use crate::{ffi, Bound, Py, PyAny, PyResult, Python};
1212
use std::borrow::Cow;
13+
use std::ffi::CString;
1314
use std::str;
1415

1516
/// Deprecated alias for [`PyString`].
@@ -216,6 +217,8 @@ impl PyString {
216217
encoding: &str,
217218
errors: &str,
218219
) -> PyResult<Bound<'py, PyString>> {
220+
let encoding = CString::new(encoding)?;
221+
let errors = CString::new(errors)?;
219222
unsafe {
220223
ffi::PyUnicode_FromEncodedObject(
221224
src.as_ptr(),
@@ -670,6 +673,31 @@ mod tests {
670673
})
671674
}
672675

676+
#[test]
677+
fn test_string_from_object() {
678+
Python::with_gil(|py| {
679+
let py_bytes = PyBytes::new(py, b"ab\xFFcd");
680+
681+
let py_string = PyString::from_object(&py_bytes, "utf-8", "ignore").unwrap();
682+
683+
let result = py_string.to_cow().unwrap();
684+
assert_eq!(result, "abcd");
685+
});
686+
}
687+
688+
#[test]
689+
fn test_string_from_obect_with_invalid_encoding_errors() {
690+
Python::with_gil(|py| {
691+
let py_bytes = PyBytes::new(py, b"abcd");
692+
693+
let result = PyString::from_object(&py_bytes, "utf\0-8", "ignore");
694+
assert!(result.is_err());
695+
696+
let result = PyString::from_object(&py_bytes, "utf-8", "ign\0ore");
697+
assert!(result.is_err());
698+
});
699+
}
700+
673701
#[test]
674702
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
675703
fn test_string_data_ucs1() {

0 commit comments

Comments
 (0)