cxx icon indicating copy to clipboard operation
cxx copied to clipboard

Raw pointers as receivers

Open nlinker opened this issue 4 years ago • 4 comments

Hi!

Let me add a question. I'd like to ask why raw pointers *const T and *mut T as receivers are unsupported?

What I often want to write is the FFI methods as

pub fn unsafe allies(self: *const Game) -> &Playerset;
// or
pub fn unsafe allies(self: *const Game) -> *mut Playerset;

but currently to make sure the shim generated by CXX fits the foreign API I have to write it as

pub fn allies(self: Pin<&mut Game>) -> Pin<&mut Playerset>;

This however brings not much safety to the call, since I need to (unsafely) dereference the foreign pointer on the Rust adapter side: https://github.com/nlinker/bwapi-xi/blob/3c9a1cc3fd2f546be21462408834923451671a39/library/src/bw/game.rs#L28-L35

So my question is whether raw pointers as receivers were switched off by design or just they have the low priority for the current time (and one may create a PR supporting this potentially)?

nlinker avatar May 03 '21 03:05 nlinker

That seems fine to allow. Nobody has needed it so far.

dtolnay avatar May 04 '21 22:05 dtolnay

That seems fine to allow. Nobody has needed it so far.

Thanks! I'm making the PR, not great progress so far, but I keep trying :-)

nlinker avatar May 08 '21 15:05 nlinker

I hit this too. AFAICT if a C++ API has:

  class Foo { void foo(); }

then there is no way to safely call it from Rust with a &Foo. The obvious way is

  impl Foo {
    unsafe fn unsafe_pin(&self) -> Pin<&mut Foo> {
      mem::transmute(self)
    }
    fn oops(&self) {
      unsafe { self.unsafe_pin().foo() }
    }
  }

but calling unsafe_pin() is insta-UB, as there's a &Foo and a &mut Foo alive simultaneously.

In practice, I think the UB won't be triggered by existing Rust (and Miri agrees: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=aafa32d497a9738378db0c096510f51e), but I don't see any way round it.

asajeffrey avatar Jun 12 '23 16:06 asajeffrey

The way to avoid the UB would be to use UnsafeCell, something like:

  struct Foo(UnsafeCell<ffi::Foo>);
  unsafe fn unsafe_pin(&self) -> Pin<&mut ffi::Foo> {
    Pin::unchecked_new(&mut *self.0.get())
  }

asajeffrey avatar Jun 12 '23 18:06 asajeffrey