Update pyo3 (#2459)

* Update pyo3

* Update pyo3 to 0.22

* Fix qemu python

* clippy

* fmt

* nautilus python

* More pyo3

* Make signature more legible
This commit is contained in:
Dominik Maier 2024-07-29 22:55:28 +02:00 committed by GitHub
parent 651ea027b9
commit c4c0fb6750
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 105 additions and 67 deletions

View File

@ -4,8 +4,8 @@ version = "0.13.2"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
pyo3 = { version = "0.18.3", features = ["extension-module"] } pyo3 = { version = "0.22", features = ["extension-module"] }
pyo3-log = "0.8.1" pyo3-log = "0.11"
libafl_sugar = { path = "../../libafl_sugar", version = "0.13.2", features = [ libafl_sugar = { path = "../../libafl_sugar", version = "0.13.2", features = [
"python", "python",
] } ] }
@ -19,7 +19,7 @@ libafl_qemu = { path = "../../libafl_qemu", version = "0.13.2", features = [
] } ] }
[build-dependencies] [build-dependencies]
pyo3-build-config = { version = "0.17" } pyo3-build-config = { version = "0.22" }
[lib] [lib]
name = "pylibafl" name = "pylibafl"

View File

@ -6,27 +6,27 @@ use pyo3::prelude::*;
/// Returns error if python libafl setup failed. /// Returns error if python libafl setup failed.
#[pymodule] #[pymodule]
#[pyo3(name = "pylibafl")] #[pyo3(name = "pylibafl")]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
pyo3_log::init(); pyo3_log::init();
let modules = py.import("sys")?.getattr("modules")?; let modules = m.py().import_bound("sys")?.getattr("modules")?;
let sugar_module = PyModule::new(py, "sugar")?; let sugar_module = PyModule::new_bound(m.py(), "sugar")?;
libafl_sugar::python_module(py, sugar_module)?; libafl_sugar::python_module(&sugar_module)?;
m.add_submodule(sugar_module)?; m.add_submodule(&sugar_module)?;
modules.set_item("pylibafl.sugar", sugar_module)?; modules.set_item("pylibafl.sugar", sugar_module)?;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
let qemu_module = PyModule::new(py, "qemu")?; let qemu_module = PyModule::new_bound(m.py(), "qemu")?;
libafl_qemu::python_module(py, qemu_module)?; libafl_qemu::python_module(&qemu_module)?;
m.add_submodule(qemu_module)?; m.add_submodule(&qemu_module)?;
modules.set_item("pylibafl.qemu", qemu_module)?; modules.set_item("pylibafl.qemu", qemu_module)?;
} }
let bolts_module = PyModule::new(py, "libafl_bolts")?; let bolts_module = PyModule::new_bound(m.py(), "libafl_bolts")?;
libafl_bolts::pybind::python_module(py, bolts_module)?; libafl_bolts::pybind::python_module(&bolts_module)?;
m.add_submodule(bolts_module)?; m.add_submodule(&bolts_module)?;
modules.set_item("pylibafl.libafl_bolts", bolts_module)?; modules.set_item("pylibafl.libafl_bolts", bolts_module)?;
Ok(()) Ok(())

View File

@ -264,7 +264,7 @@ arrayvec = { version = "0.7.4", optional = true, default-features = false } # us
const_format = "0.2.32" # used for providing helpful compiler output const_format = "0.2.32" # used for providing helpful compiler output
const_panic = "0.2.8" # similarly, for formatting const panic output const_panic = "0.2.8" # similarly, for formatting const panic output
pyo3 = { version = "0.18.3", optional = true } # For nautilus pyo3 = { version = "0.22", optional = true } # For nautilus
regex-syntax = { version = "0.8.3", optional = true } # For nautilus regex-syntax = { version = "0.8.3", optional = true } # For nautilus
# optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable)

View File

@ -5,7 +5,7 @@ use hashbrown::HashSet;
use libafl_bolts::rands::Rand; use libafl_bolts::rands::Rand;
use pyo3::{ use pyo3::{
prelude::{PyObject, PyResult, Python}, prelude::{PyObject, PyResult, Python},
types::{PyBytes, PyString, PyTuple}, types::{PyAnyMethods, PyBytes, PyBytesMethods, PyString, PyStringMethods, PyTuple},
FromPyObject, PyTypeInfo, FromPyObject, PyTypeInfo,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -85,13 +85,14 @@ impl<'data, 'tree: 'data, 'ctx: 'data, W: Write, T: TreeLike> Unparser<'data, 't
.into_iter() .into_iter()
.map(io::Cursor::into_inner) .map(io::Cursor::into_inner)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let byte_arrays = bufs.iter().map(|b| PyBytes::new(py, b)); let byte_arrays = bufs.iter().map(|b| PyBytes::new_bound(py, b));
let res = expr.call1(py, PyTuple::new(py, byte_arrays))?; let res = expr.call1(py, PyTuple::new_bound(py, byte_arrays))?;
if PyString::is_type_of(res.as_ref(py)) { let bound = res.bind(py);
let pystr = <&PyString>::extract(res.as_ref(py))?; if PyString::is_type_of_bound(bound) {
let pystr = bound.downcast::<PyString>()?;
self.write(pystr.to_string_lossy().as_bytes()); self.write(pystr.to_string_lossy().as_bytes());
} else if PyBytes::is_type_of(res.as_ref(py)) { } else if PyBytes::is_type_of_bound(bound) {
let pybytes = <&PyBytes>::extract(res.as_ref(py))?; let pybytes = bound.downcast::<PyBytes>()?;
self.write(pybytes.as_bytes()); self.write(pybytes.as_bytes());
} else { } else {
return Err(pyo3::exceptions::PyValueError::new_err( return Err(pyo3::exceptions::PyValueError::new_err(

View File

@ -164,7 +164,7 @@ clap = { version = "4.5", features = [
], optional = true } # CLI parsing, for libafl_bolts::cli / the `cli` feature ], optional = true } # CLI parsing, for libafl_bolts::cli / the `cli` feature
log = { version = "0.4" } log = { version = "0.4" }
pyo3 = { version = "0.18", optional = true, features = ["serde", "macros"] } pyo3 = { version = "0.22", optional = true, features = ["serde", "macros"] }
# optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable)
serial_test = { version = "3", optional = true, default-features = false, features = [ serial_test = { version = "3", optional = true, default-features = false, features = [

View File

@ -623,7 +623,7 @@ impl From<pyo3::PyErr> for Error {
pyo3::Python::with_gil(|py| { pyo3::Python::with_gil(|py| {
if err.matches( if err.matches(
py, py,
pyo3::types::PyType::new::<pyo3::exceptions::PyKeyboardInterrupt>(py), pyo3::types::PyType::new_bound::<pyo3::exceptions::PyKeyboardInterrupt>(py),
) { ) {
Self::shutting_down() Self::shutting_down()
} else { } else {
@ -1056,7 +1056,7 @@ pub unsafe fn set_error_print_panic_hook(new_stderr: RawFd) {
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use pyo3::{pymodule, types::PyModule, PyResult, Python}; use pyo3::{pymodule, types::PyModule, Bound, PyResult};
#[macro_export] #[macro_export]
macro_rules! unwrap_me_body { macro_rules! unwrap_me_body {
@ -1188,8 +1188,8 @@ pub mod pybind {
#[pymodule] #[pymodule]
#[pyo3(name = "libafl_bolts")] #[pyo3(name = "libafl_bolts")]
/// Register the classes to the python module /// Register the classes to the python module
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
crate::rands::pybind::register(py, m)?; crate::rands::pybind::register(m)?;
Ok(()) Ok(())
} }
} }

View File

@ -689,7 +689,7 @@ pub mod pybind {
} }
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug)]
enum PythonRandWrapper { enum PythonRandWrapper {
Std(Py<PythonStdRand>), Std(Py<PythonStdRand>),
} }
@ -697,7 +697,7 @@ pub mod pybind {
/// Rand Trait binding /// Rand Trait binding
#[pyclass(unsendable, name = "Rand")] #[pyclass(unsendable, name = "Rand")]
#[allow(clippy::unsafe_derive_deserialize)] #[allow(clippy::unsafe_derive_deserialize)]
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug)]
pub struct PythonRand { pub struct PythonRand {
wrapper: PythonRandWrapper, wrapper: PythonRandWrapper,
} }
@ -730,7 +730,7 @@ pub mod pybind {
} }
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PythonStdRand>()?; m.add_class::<PythonStdRand>()?;
m.add_class::<PythonRand>()?; m.add_class::<PythonRand>()?;
Ok(()) Ok(())

View File

@ -123,7 +123,7 @@ paste = "1"
enum-map = "2.7" enum-map = "2.7"
serde_yaml = { version = "0.9", optional = true } # For parsing the injections yaml file serde_yaml = { version = "0.9", optional = true } # For parsing the injections yaml file
toml = { version = "0.8.13", optional = true } # For parsing the injections toml file toml = { version = "0.8.13", optional = true } # For parsing the injections toml file
pyo3 = { version = "0.18", optional = true, features = ["multiple-pymethods"] } pyo3 = { version = "0.22", optional = true, features = ["multiple-pymethods"] }
bytes-utils = "0.1" bytes-utils = "0.1"
typed-builder = "0.18" typed-builder = "0.18"
memmap2 = "0.9" memmap2 = "0.9"
@ -132,7 +132,7 @@ document-features = { version = "0.2", optional = true }
[build-dependencies] [build-dependencies]
libafl_qemu_build = { path = "./libafl_qemu_build", version = "0.13.2" } libafl_qemu_build = { path = "./libafl_qemu_build", version = "0.13.2" }
pyo3-build-config = { version = "0.21", optional = true } pyo3-build-config = { version = "0.22", optional = true }
rustversion = "1.0" rustversion = "1.0"
bindgen = "0.69" bindgen = "0.69"
cc = "1.0" cc = "1.0"

View File

@ -59,9 +59,9 @@ num_enum = "0.7"
libc = "0.2" libc = "0.2"
strum = "0.26" strum = "0.26"
strum_macros = "0.26" strum_macros = "0.26"
pyo3 = { version = "0.18", optional = true } pyo3 = { version = "0.22", optional = true }
[build-dependencies] [build-dependencies]
libafl_qemu_build = { path = "../libafl_qemu_build", version = "0.13.2" } libafl_qemu_build = { path = "../libafl_qemu_build", version = "0.13.2" }
pyo3-build-config = { version = "0.21", optional = true } pyo3-build-config = { version = "0.22", optional = true }
rustversion = "1.0" rustversion = "1.0"

View File

@ -83,6 +83,7 @@ macro_rules! extern_c_checked {
unsafe impl Sync for [<__ $c_var:upper _STRUCT__>] {} unsafe impl Sync for [<__ $c_var:upper _STRUCT__>] {}
#[cfg_attr(nightly, used(linker))] #[cfg_attr(nightly, used(linker))]
#[allow(unused_unsafe)]
static [<__ $c_var:upper __>]: [<__ $c_var:upper _STRUCT__>] = unsafe { [<__ $c_var:upper _STRUCT__>] { member: core::ptr::addr_of!($c_var) } }; static [<__ $c_var:upper __>]: [<__ $c_var:upper _STRUCT__>] = unsafe { [<__ $c_var:upper _STRUCT__>] { member: core::ptr::addr_of!($c_var) } };
} }
@ -102,6 +103,7 @@ macro_rules! extern_c_checked {
unsafe impl Sync for [<__ $c_var:upper _STRUCT__>] {} unsafe impl Sync for [<__ $c_var:upper _STRUCT__>] {}
#[cfg_attr(nightly, used(linker))] #[cfg_attr(nightly, used(linker))]
#[allow(unused_unsafe)]
static mut [<__ $c_var:upper __>]: [<__ $c_var:upper _STRUCT__>] = unsafe { [<__ $c_var:upper _STRUCT__>] { member: core::ptr::addr_of!($c_var) } }; static mut [<__ $c_var:upper __>]: [<__ $c_var:upper _STRUCT__>] = unsafe { [<__ $c_var:upper _STRUCT__>] { member: core::ptr::addr_of!($c_var) } };
} }

View File

@ -79,20 +79,22 @@ use pyo3::prelude::*;
#[pymodule] #[pymodule]
#[pyo3(name = "libafl_qemu")] #[pyo3(name = "libafl_qemu")]
#[allow(clippy::items_after_statements, clippy::too_many_lines)] #[allow(clippy::items_after_statements, clippy::too_many_lines)]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
let regsm = PyModule::new(py, "regs")?; use pyo3::types::PyString;
let regsm = PyModule::new_bound(m.py(), "regs")?;
for r in Regs::iter() { for r in Regs::iter() {
let v: i32 = r.into(); let v: i32 = r.into();
regsm.add(&format!("{r:?}"), v)?; regsm.add(PyString::new_bound(m.py(), &format!("{r:?}")), v)?;
} }
m.add_submodule(regsm)?; m.add_submodule(&regsm)?;
let mmapm = PyModule::new(py, "mmap")?; let mmapm = PyModule::new_bound(m.py(), "mmap")?;
for r in sys::MmapPerms::iter() { for r in sys::MmapPerms::iter() {
let v: i32 = r.into(); let v: i32 = r.into();
mmapm.add(&format!("{r:?}"), v)?; mmapm.add(PyString::new_bound(m.py(), &format!("{r:?}")), v)?;
} }
m.add_submodule(mmapm)?; m.add_submodule(&mmapm)?;
m.add_class::<sys::MapInfo>()?; m.add_class::<sys::MapInfo>()?;

View File

@ -934,25 +934,24 @@ impl QemuHooks {
#[pymethods] #[pymethods]
impl SyscallHookResult { impl SyscallHookResult {
#[new] #[new]
#[pyo3(signature = (
value=None
))]
#[must_use] #[must_use]
pub fn new(value: Option<GuestAddr>) -> Self { pub fn new(value: Option<GuestAddr>) -> Self {
value.map_or( Self::new_internal(value)
Self {
retval: 0,
skip_syscall: false,
},
|v| Self {
retval: v,
skip_syscall: true,
},
)
} }
} }
#[cfg(not(feature = "python"))]
impl SyscallHookResult { impl SyscallHookResult {
#[cfg(not(feature = "python"))]
#[must_use] #[must_use]
pub fn new(value: Option<GuestAddr>) -> Self { pub fn new(value: Option<GuestAddr>) -> Self {
Self::new_internal(value)
}
#[must_use]
fn new_internal(value: Option<GuestAddr>) -> Self {
value.map_or( value.map_or(
Self { Self {
retval: 0, retval: 0,

View File

@ -233,7 +233,11 @@ impl Qemu {
pub mod pybind { pub mod pybind {
use libafl_qemu_sys::{GuestAddr, MmapPerms}; use libafl_qemu_sys::{GuestAddr, MmapPerms};
use pyo3::{ use pyo3::{
exceptions::PyValueError, pymethods, types::PyInt, FromPyObject, PyObject, PyResult, Python, conversion::FromPyObject,
exceptions::PyValueError,
pymethods,
types::{PyAnyMethods, PyInt},
Bound, PyObject, PyResult, Python,
}; };
use crate::{pybind::Qemu, qemu::hooks::SyscallHookResult}; use crate::{pybind::Qemu, qemu::hooks::SyscallHookResult};
@ -258,17 +262,17 @@ pub mod pybind {
let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7); let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7);
Python::with_gil(|py| { Python::with_gil(|py| {
let ret = obj.call1(py, args).expect("Error in the syscall hook"); let ret = obj.call1(py, args).expect("Error in the syscall hook");
let any = ret.as_ref(py); let any = ret.bind(py);
if any.is_none() { if any.is_none() {
SyscallHookResult::new(None) SyscallHookResult::new(None)
} else { } else {
let a: Result<&PyInt, _> = any.downcast(); let a: Result<&Bound<'_, PyInt>, _> = any.downcast_exact();
if let Ok(i) = a { if let Ok(i) = a {
SyscallHookResult::new(Some( SyscallHookResult::new(Some(
i.extract().expect("Invalid syscall hook return value"), i.extract().expect("Invalid syscall hook return value"),
)) ))
} else { } else {
SyscallHookResult::extract(any) SyscallHookResult::extract_bound(ret.bind(py))
.expect("The syscall hook must return a SyscallHookResult") .expect("The syscall hook must return a SyscallHookResult")
} }
} }

View File

@ -53,7 +53,7 @@ ppc = ["libafl_qemu/ppc"]
hexagon = ["libafl_qemu/hexagon"] hexagon = ["libafl_qemu/hexagon"]
[build-dependencies] [build-dependencies]
pyo3-build-config = { version = "0.21", optional = true } pyo3-build-config = { version = "0.22", optional = true }
[dependencies] [dependencies]
libafl = { path = "../libafl", version = "0.13.2" } libafl = { path = "../libafl", version = "0.13.2" }
@ -64,7 +64,7 @@ libafl_targets = { path = "../libafl_targets", version = "0.13.2" }
document-features = { version = "0.2", optional = true } document-features = { version = "0.2", optional = true }
typed-builder = "0.18" # Implement the builder pattern at compiletime typed-builder = "0.18" # Implement the builder pattern at compiletime
pyo3 = { version = "0.18", optional = true } pyo3 = { version = "0.22", optional = true }
log = "0.4.20" log = "0.4.20"
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]

View File

@ -335,6 +335,16 @@ pub mod pybind {
/// Create a new [`ForkserverBytesCoverageSugar`] /// Create a new [`ForkserverBytesCoverageSugar`]
#[new] #[new]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[pyo3(signature = (
input_dirs,
output_dir,
broker_port,
cores,
use_cmplog=None,
iterations=None,
tokens_file=None,
timeout=None
))]
fn new( fn new(
input_dirs: Vec<PathBuf>, input_dirs: Vec<PathBuf>,
output_dir: PathBuf, output_dir: PathBuf,
@ -377,7 +387,7 @@ pub mod pybind {
} }
/// Register the module /// Register the module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<ForkserverBytesCoverageSugar>()?; m.add_class::<ForkserverBytesCoverageSugar>()?;
Ok(()) Ok(())
} }

View File

@ -392,6 +392,16 @@ pub mod pybind {
/// Create a new [`InMemoryBytesCoverageSugar`] /// Create a new [`InMemoryBytesCoverageSugar`]
#[new] #[new]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[pyo3(signature = (
input_dirs,
output_dir,
broker_port,
cores,
use_cmplog=None,
iterations=None,
tokens_file=None,
timeout=None
))]
fn new( fn new(
input_dirs: Vec<PathBuf>, input_dirs: Vec<PathBuf>,
output_dir: PathBuf, output_dir: PathBuf,
@ -424,7 +434,7 @@ pub mod pybind {
.cores(&self.cores) .cores(&self.cores)
.harness(|buf| { .harness(|buf| {
Python::with_gil(|py| -> PyResult<()> { Python::with_gil(|py| -> PyResult<()> {
let args = (PyBytes::new(py, buf),); // TODO avoid copy let args = (PyBytes::new_bound(py, buf),); // TODO avoid copy
harness.call1(py, args)?; harness.call1(py, args)?;
Ok(()) Ok(())
}) })
@ -440,7 +450,7 @@ pub mod pybind {
} }
/// Register the module /// Register the module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<InMemoryBytesCoverageSugar>()?; m.add_class::<InMemoryBytesCoverageSugar>()?;
Ok(()) Ok(())
} }

View File

@ -86,15 +86,15 @@ use pyo3::prelude::*;
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[pymodule] #[pymodule]
#[pyo3(name = "libafl_sugar")] #[pyo3(name = "libafl_sugar")]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
inmemory::pybind::register(py, m)?; inmemory::pybind::register(m)?;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
qemu::pybind::register(py, m)?; qemu::pybind::register(m)?;
} }
#[cfg(unix)] #[cfg(unix)]
{ {
forkserver::pybind::register(py, m)?; forkserver::pybind::register(m)?;
} }
Ok(()) Ok(())
} }

View File

@ -494,6 +494,16 @@ pub mod pybind {
/// Create a new [`QemuBytesCoverageSugar`] /// Create a new [`QemuBytesCoverageSugar`]
#[new] #[new]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[pyo3(signature = (
input_dirs,
output_dir,
broker_port,
cores,
use_cmplog=None,
iterations=None,
tokens_file=None,
timeout=None
))]
fn new( fn new(
input_dirs: Vec<PathBuf>, input_dirs: Vec<PathBuf>,
output_dir: PathBuf, output_dir: PathBuf,
@ -526,7 +536,7 @@ pub mod pybind {
.cores(&self.cores) .cores(&self.cores)
.harness(|buf| { .harness(|buf| {
Python::with_gil(|py| -> PyResult<()> { Python::with_gil(|py| -> PyResult<()> {
let args = (PyBytes::new(py, buf),); // TODO avoid copy let args = (PyBytes::new_bound(py, buf),); // TODO avoid copy
harness.call1(py, args)?; harness.call1(py, args)?;
Ok(()) Ok(())
}) })
@ -542,7 +552,7 @@ pub mod pybind {
} }
/// Register this class /// Register this class
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<QemuBytesCoverageSugar>()?; m.add_class::<QemuBytesCoverageSugar>()?;
Ok(()) Ok(())
} }