tizoc / ocaml-interop

OCaml<->Rust FFI with an emphasis on safety.
MIT License
134 stars 21 forks source link

Increase type safety at the FFI boundary #30

Open g2p opened 3 years ago

g2p commented 3 years ago

Currently there's implicit trust in the fact that OCaml<T> values are created with the right type. OCaml::new is marked unsafe as it should, but there are plenty of "safe" wrappers that don't guarantee that we have the right OCaml type. For example, OCamlClosure doesn't have type parameters, and the various call functions use caller-chosen types.

As more complex OCaml<T> types get implemented for various T, it would be good to have these guarantees at the right boundary, so that checks are done at most once and the specializations can trust that they work with the right in-memory representation.

One way to do that would be to introduce a trait that T implements that checks that a RawOCaml is safe to parse as an OCaml<T>.

As for the ocaml! macro which generates most conversions to OCaml<T>, I don't know the overhead of using the safe interfaces every time; assuming the declarations stay well-typed here may or may not be a good idea. For now I'd like to at least ensure safe interfaces exist.

tizoc commented 3 years ago

Note that OCamlClosure is not exposed and only meant for internal use, but you are right, all it's functions, although not marked unsafe, are. ocaml! is the only public interface to OCaml functions.

About type-safety at the boundaries, my intention for improving this when I have time to get into it, is to generate glue code for all definitions (OCaml code from Rust definitions, and Rust code from OCaml definitions), for both composite datatypes and functions. Then on each side you will interact with this autogenerated glue code which you know is correct. That way you can get the type-checkers from both languages involved in the correctness validation at the boundaries, all at compile-time.

Right now if you make a mistake when declaring a function, struct, etc (by missing a field/parameter, or using the incorrect order), things will go wrong because there is no safeguard at compile time.