Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsoundness with Fn trait #89

Open
Noratrieb opened this issue Nov 21, 2022 · 3 comments
Open

Unsoundness with Fn trait #89

Noratrieb opened this issue Nov 21, 2022 · 3 comments

Comments

@Noratrieb
Copy link

The Fn trait allows converting arbitrary integers into function pointers.

use lunatic::function::reference::Fn;

<fn() as Fn<fn()>>::from_id(0)();

This creates a null fn() pointer which is instant undefined behavior.

@bkolobara
Copy link
Contributor

Thanks @Nilstrieb for bringing this up. This is a bit of an ugly workaround for the fact that Rust doesn't let us implement traits for function pointers. I talked a bit more about the issue here: https://internals.rust-lang.org/t/extending-implicit-coercion-of-function-items-to-function-pointers-during-trait-resolution/17093

I have an idea on how to make this interface safer and more ergonomic. One of my posts from discord:

The main reason why we can't use closures as entry points into new processes is that closures can hold data and have an anonymous type. This means that we can't serialize the data before passing it to a new process. However, we might be able to find a middle-ground here.

It is safe to send captured data to another process if it can be done as a memcopy and doesn't require serialization. Luckily, Rust has a built-in marker trait for this, Copy. Copy is also an auto-trait, meaning that it will be implemented for closures if all members also implement it. That's why I think that a type like this would work for entry functions:

trait Entry {}
impl<T> Entry for T
    where T: FnOnce() + Copy + 'static

Copy is also implemented for references and pointer types, but we work around this by requiring a 'static lifetime. The main idea is just to take T and memcopy it as is into the new process.

This would have two benefits for us:

  1. It relaxes the requirement that each entry function can't capture anything to "an entry function can capture copy types".
  2. It would give us more flexibility to express process properties based only on entry function signatures. For example, fn(Mailbox<T>) would spawn a regular process, fn(Protocol<T>) a protocol, etc.

@Noratrieb
Copy link
Author

This would also need a T: Send bound, but doesn't sound bad otherwise.

@bkolobara
Copy link
Contributor

This would also need a T: Send bound, but doesn't sound bad otherwise.

I don't think so. Lunatic processes use different memory spaces, Send and Sync don't mean anything in that case. One process can never reference/observe the memory of another.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants