I am wary of PyO3. The last time I seriously considered using it (a little under 2 years ago), it felt like basically every feature I looked at fell into one of two categories:
- Either it already existed in
rust_cpython
(which PyO3 is a fork of)... - ...or I could easily come up with a way to invoke UB with it.
After reporting the issues I found, I even had to work to convince the author that the UB was a problem!
In the time since then, a major shitstorm happened with unsafe code in the actix
crate by the same author. I would like to think he has learned his lesson, but for me, the damage has been done; I have difficulty bringing myself to use the crate without heavy review. (and there's simply too much of it for me to review!)
And even looking at it today, I see things that make sirens go off in my head:
fn try_from_mut<V: Into<&'v PyAny>>(
value: V
) -> Result<&'v mut Self, PyDowncastError>
Surely this can be called twice on a &'v PyAny
to get aliasing mutable references to Self
?
impl<'a, T> std::convert::From<&'a T> for PyObject
where
T: AsPyPointer;
Where did the lifetime go? Moreover, why on Earth does this even exist? I can only assume there's some way to get a (Edit: I just noticed the &'a T
back out of the PyObject
, thereby allowing a use-after-free?AsPyPointer
bound. That might make this less bad)
self.inner
.push_back(unsafe { mem::MaybeUninit::uninit().assume_init() });
mem::MaybeUninit::uninit().assume_init()
is explicitly documented as UB even for types like u32
that have no invalid bit patterns.
I'm not certain that I have the time and energy to hunt down and report examples of all the ways that one can still invoke UB using this crate. I'd feel much more comfortable just contributing to rust_cpython
to add any missing features.