Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/6052.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed issue that `PyFrame::builtins` could return a non-dict object.
31 changes: 29 additions & 2 deletions src/types/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,17 @@ impl<'py> PyFrameMethods<'py> for Bound<'py, PyFrame> {
// - `self` is a `PyFrameObject`
// - `PyFrame_GetBuiltins` returns an owned reference
// - the result can not be null
// - the result is a dict object
unsafe {
ffi::PyFrame_GetBuiltins(self.as_ptr().cast())
.assume_owned_unchecked(self.py())
.cast_into_unchecked()
.cast_into()
// The result is expected (and documented) to be a dict object, however it is
// possible for Python code to overwrite `__builtins__` with any arbitrary object.
// As reasonable code should never do this, we panic here for correctness in case
// the type does not match.
//
// See https://github.com/PyO3/pyo3/issues/6048
.expect("`PyFrame_GetBuiltins` returns a `dict`")
Comment thread
ngoldbaum marked this conversation as resolved.
}
}

Expand Down Expand Up @@ -304,6 +310,27 @@ def outer():
})
}

#[test]
#[cfg(all(Py_3_11, not(Py_LIMITED_API)))]
#[should_panic(expected = "`PyFrame_GetBuiltins` returns a `dict`")]
fn test_frame_builtins_panics_on_type_error() {
use crate::types::PyAnyMethods as _;
Python::attach(|py| -> PyResult<()> {
let sys = py.import("sys")?;
let globals = PyDict::new(py);
globals.set_item("getframe", sys.getattr("_getframe")?)?;
globals.set_item("__builtins__", py.eval(c"object()", None, None)?)?;
py.run(c"frame = getframe()", Some(&globals), None)?;
let frame: Bound<'_, PyFrame> = globals.get_item("frame")?.cast_into()?;

// This should panic, as `__builtins__` is not a dict
let _builtins = frame.builtins();

Ok(())
})
.unwrap();
}

#[test]
#[cfg(all(Py_3_11, not(Py_LIMITED_API)))]
fn test_frame_get_globals() {
Expand Down
Loading