ffi: fix PyStatus._type

The field wasn't defined previously. And the enum wasn't defined as
`[repr(C)]`.

This missing field could result in memory corruption if a Rust-allocated
`PyStatus` was passed to a Python API, which could perform an
out-of-bounds write. In my code, the out-of-bounds write corrupted a
variable on the stack, leading to a segfault due to illegal memory
access. However, this crash only occurred on Rust 1.54! So I initially
mis-attribted it as a compiler bug / regression. It appears that a
low-level Rust change in 1.54.0 changed the LLVM IR in such a way to
cause LLVM optimization passes to produce sufficiently different
assembly code, tickling the crash. See
https://github.com/rust-lang/rust/issues/87947 if you want to see
the wild goose chase I went on in Rust / LLVM land to potentially
pin this on a compiler bug.

Lessen learned: Rust crashes are almost certainly due to use of
`unsafe`.
This commit is contained in:
Gregory Szorc 2021-08-13 20:51:26 -07:00
parent 254ea53f3f
commit d3762a679f
2 changed files with 3 additions and 0 deletions

View file

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed ### Fixed
- Restrict FFI definitions `PyGILState_Check` and `Py_tracefunc` to the unlimited API. [#1787](https://github.com/PyO3/pyo3/pull/1787) - Restrict FFI definitions `PyGILState_Check` and `Py_tracefunc` to the unlimited API. [#1787](https://github.com/PyO3/pyo3/pull/1787)
- Add missing `_type` field to `PyStatus` struct definition.
## [0.14.2] - 2021-08-09 ## [0.14.2] - 2021-08-09

View file

@ -4,6 +4,7 @@ use crate::ffi::Py_ssize_t;
use libc::wchar_t; use libc::wchar_t;
use std::os::raw::{c_char, c_int, c_ulong}; use std::os::raw::{c_char, c_int, c_ulong};
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum _PyStatus_TYPE { pub enum _PyStatus_TYPE {
_PyStatus_TYPE_OK = 0, _PyStatus_TYPE_OK = 0,
@ -14,6 +15,7 @@ pub enum _PyStatus_TYPE {
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct PyStatus { pub struct PyStatus {
pub _type: _PyStatus_TYPE,
pub func: *const c_char, pub func: *const c_char,
pub err_msg: *const c_char, pub err_msg: *const c_char,
pub exitcode: c_int, pub exitcode: c_int,