Rust FFI Panic Barriers
Relevant source files
The following files were used as context for generating this wiki page:
Rust Foreign Function Interface (FFI) Panic Barriers protect the Spotty application from process-wide crashes caused by Rust panics. Every pub extern "C" function exported by the spotty-playback library must enter through these named panic-barrier helpers. These barriers catch panics at the boundary and map them to defined C-compatible sentinel errors, preventing unwinding across the FFI boundary which would result in undefined behavior.
Sources: Backend/spotty-playback/src/tests.rs:599-605, Backend/spotty-playback/AGENTS.md:20-23
Architecture and Implementation
The panic barrier system centralizes the safety logic within ffi.rs. Each barrier wraps the execution of a Rust closure in a catch_unwind block. If the closure panics, the barrier returns a conservative default value (such as ERROR_GENERAL or null) instead of allowing the panic to propagate to the Swift caller.
Data Flow for FFI Calls
The following diagram illustrates how an external call from the Swift layer is processed through a panic barrier before reaching the internal Rust logic.
The diagram shows the execution flow where the Panic Barrier acts as a wrapper around internal logic to intercept failures.
Sources: Backend/spotty-playback/src/tests.rs:604-635, Backend/spotty-playback/AGENTS.md:20-25
Core Panic Barrier Helpers
The project defines several specialized barrier functions based on the expected return type of the FFI export.
| Barrier Function | Return Type | Failure Value | Description |
|---|---|---|---|
ffi_command | i32 | ERROR_GENERAL | Used for commands that return a status code. |
ffi_query_i32 | i32 | 0 | Returns a signed 32-bit integer or zero on panic. |
ffi_query_u32 | u32 | 0 | Returns an unsigned 32-bit integer or zero on panic. |
ffi_query_u8 | u8 | 0 | Returns a byte or zero on panic. |
ffi_query_bool | bool | false | Returns a boolean or false on panic. |
ffi_owned_string | *mut c_char | null | Returns a C-string pointer or null on panic. |
ffi_owned_ptr | *mut T | null | Returns a generic pointer or null on panic. |
ffi_void | () | N/A | Executes code that returns nothing; panic is a no-op. |
Sources: Backend/spotty-playback/src/tests.rs:599-606, Backend/spotty-playback/src/tests.rs:637-645
Enforcement and Validation
The project enforces the use of these barriers through structural ABI tests. These tests walk the Rust source files to ensure every pub extern "C" function uses a barrier and that no production code outside of runtime.rs calls RUNTIME.block_on directly.
Safety Constraints
- No Unwinding: Barriers ensure panics never unwind into C/Swift code. Sources: Backend/spotty-playback/AGENTS.md:24-25
- No Lock Holding: Rust locks must not be held when invoking Swift callbacks to prevent deadlocks. Sources: Backend/spotty-playback/AGENTS.md:24-25
- Runtime Re-entry: The helper
refuse_if_nested_runtimeis used to detect and prevent illegal nestedblock_oncalls, which returnERROR_GENERAL. Sources: Backend/spotty-playback/AGENTS.md:20-23, Backend/spotty-playback/src/tests.rs:658-675
Verification Sequence
This sequence diagram shows how the exported_c_functions_enter_through_the_panic_barrier test validates implementation compliance.
Sources: Backend/spotty-playback/src/tests.rs:684-705
Summary
Rust FFI Panic Barriers are critical security and stability components in Spotty. By wrapping all C-exported functions in catch_unwind logic, the system guarantees that Rust-level failures remain contained. This architecture allows the Swift frontend to receive predictable error codes instead of suffering from undefined behavior or immediate process termination.
Sources: SECURITY.md:22-30, Backend/spotty-playback/AGENTS.md:20-25