Rantanen / intercom

Object based cross-language FFI for Rust
MIT License
63 stars 7 forks source link

Drop partially converted output values #171

Closed Rantanen closed 4 years ago

Rantanen commented 4 years ago

When handling ExternOutput conversions, Intercom currently does these conversions one by one. As these conversions may fail, at the moment of failure (which is handled with ? by interrupting the conversions) some of the values may be converted and some aren't.

Foreign representations that require manual memory management (Release calls for COM pointers for example) will leak if the error occurs while such values exist.

The new implementation fixes this in two ways depending on the scenario where the ExternOutput values occur.

Rust-to-Foreign invocations

In Rust-to-Foreign invocations the function ExternOutput values are created in the foreign function and the ownership is handed to Rust. In this case it is enough to ensure that all ExternOutput values are converted to managed Rust types before unwrapping the returned ComResults with ?.

Rust-from-Foreign invocations

In Rust-from-Foreign invocations the ExternOutput values are created in Rust and converted to foreign types when returned to the foreign functions. If these conversions fail, Intercom must ensure that all previously converted values are released properly. The values that have yet to be converted are still managed by Rust memory management and will be released as normal.

The implementation here involves OutputGuard<TType> type that holds the TType::ForeignType values. During normal return handling the foreign value is moved out of the OutputGuard without any cleanup but if the OutputGuard is dropped without consuming (as is the case if ? returns while existing OutputGuards are in scope), the OutputGuard cleans up the ForeignTypes. By default this means converting the TType::ForeignType back to TType, which should already handle memory for the successful Rust-to-Foreign scenario.

It is possible for a TType to override the default behavior by providing their own drop_foreign_output implementation. Currently this isn't used, but it is likely that various String-types would put this into use to avoid things like the overhead of the UTF-8 validation when no actual String value is needed.