--- tags: prusti, prusti-student-projects --- # Prusti PW project: FFI specification project dates: 19. 9. 2022 - (mid-January 2023) meetings: Mondays at 13:00, https://ethz.zoom.us/j/68834336092 ## Attaching specs to extern functions ```rust= extern "C" { #[ensures(input >= 0 ==> result == input)] #[ensures(input < 0 ==> result == -input)] fn abs(input: i32) -> i32; } ``` - [x] currently runs into a compiler error - we are expanding the specification item for the precondition within the `extern "C"` block - need something similar to `#[refine_trait_spec]` - [x] if fixed manually (using `PRUSTI_PRINT_DESUGARED_SPECS`), specifications are still not attached to the call - see what goes on in the MIR representation - does the spec collector find the specs? - does the call resolve to the same `DefId`? - does an extern call use the `Call` terminator in MIR? - [x] make sure specs can be exported across crate boundaries ## Set up CI - (unit) test specifications on native functions - compile a `.so`/`.dylib`/`.dll` with a simple function in C ## Features needed for Python C extension APIs - note: based on the internals of [PyO3](https://github.com/PyO3/pyo3/) - this is an "FFI generator" (i.e. wraps the raw C APIs in a nicer, more declarative interface) - larger scope and harder to verify - the [actual internals](https://github.com/PyO3/pyo3/tree/main/pyo3-ffi) use the C API - Python manual reference - https://docs.python.org/3/extending/index.html#creating-extensions-without-third-party-tools - https://docs.python.org/3/c-api/index.html - support for [opaque types](https://github.com/PyO3/pyo3/blob/554bc84c885e296622b629245b610623cd02c878/pyo3-ffi/src/lib.rs#L251-L259), such as [`PyObject*`](https://github.com/PyO3/pyo3/blob/9777faddc6464699f6580fb7b176989aacb5193f/pyo3-ffi/src/object.rs#L8-L9) - make sure the generated snapshot domain is empty - pure functions over opaque types, e.g. [`Py_IsNone`](https://github.com/PyO3/pyo3/blob/9777faddc6464699f6580fb7b176989aacb5193f/pyo3-ffi/src/object.rs#L495) - incl. marking external functions as pure - incref/decref -> obligations - incref creates an obligation - decref consumes it - pass it around? certain C APIs expect incref'd instances, although docs are very unclear for this - assorted topics to tackle - [exception handling](https://docs.python.org/3/c-api/exceptions.html) - deal with exceptions (obligation?) after calls that might throw - [buffer protocol](https://docs.python.org/3/c-api/buffer.html) - verify accesses are in-bounds - [survey of common problems](https://onlinelibrary.wiley.com/doi/abs/10.1002/smr.2507), table on page 11: - mishandling exceptions - insufficient error checking - memory management flaws - integer overflows - API evolution flaws - buffer overflow - reference counting errors - type misuses - GIL bugs ## Encoding obligations in Prusti - pure functions are insufficient for resource reasoning without manual heap versioning ``` #[pure] fn resource(uid: i32); #[requires(resource(uid))] #[ensures(...?)] // resource(uid) will always be true in the postcondition fn consume_resource(uid: i32) { ... } ``` - use owned types: arguments for consumed resources, additional return values for created resources ``` struct Resource; fn consume_resource(x: Resource) { ... } ``` - ideally: ghost arguments, for now actual (ZST) arguments and wrappers over external APIs - [`ManuallyDrop`](https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html) on resource types to prevent leakage and to model obligations specifically (cannot simply forget an obligation resource) - `#[resource]` or `#[obligation]` attributes in Prusti? - ensure type is ZST - ensure `ManuallyDrop` is implemented and the correct Prusti-specific error is emitted - (future: ensure type is only used in ghost code, ghost arguments, ghost returns, ghost fields)