0

I've searched everywhere for this and found various answers for similar things but nothing specific yet.

Context: my networking subsystem is extendable with new message types. That rules out using an enum.

Is it valid to convert a Box<dyn Trait> to a Box<Concrete> using x_ptr as *const Box<Concrete> where x_ptr is an unsafe pointer to Trait?

If so what restrictions does it place on Concrete or Trait?

I looked at downcast() implementations for Any in the repo, and indeed it seems to just be casting between pointer types. So I assume what I am trying to do is indeed valid.

Full example below:

use std::rc::Rc;

trait A {
    fn name(&self) -> &str;
}

struct B {
    x: u32
}

impl B {
}

impl A for B {
    fn name(&self) -> &str {
        "hello"
    }
}

fn main() {
    let x: Rc<Box<dyn A>> = Rc::new(Box::new(B { x: 110 }));
    println!("count after creating x = {}", Rc::strong_count(&x));
    let x_ptr = Rc::into_raw(x.clone());
    println!("count after creating x = {}", Rc::strong_count(&x));
    
    let y = unsafe {
        // Convert back to an `Rc` to prevent leak.
        let x: Rc<Box<B>> = Rc::from_raw(x_ptr as *const Box<B>);
        println!("{}", x.x);
        println!("{}", x.name());
        x

        // Further calls to `Rc::from_raw(x_ptr)` would be memory-unsafe.
    };

    let z = y.clone();
    println!("count after creating x = {}", Rc::strong_count(&x));

    // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling!
}

Yields desired output of:

count after creating x = 1
count after creating x = 2
110
hello
count after creating x = 3
  • "my networking subsystem is extendable with new message types. That rules out using an enum." Why? Why can't you create an `non_exhaustive` `enum`? This would allow you to add new `enum variants` in the future. – WBuck Mar 05 '21 at 12:46
  • I want new types added via the API, not through modifying the enum in my code. – Ignatio Mobius Mar 05 '21 at 12:48
  • Why do you repeat the question? ([Arc> into Arc> using unsafe pointers](https://stackoverflow.com/questions/66490750/arcboxdyn-trait-into-arcboxconcrete-using-unsafe-pointers)) – Rabbid76 Mar 05 '21 at 12:54
  • That post was closed by the moderators because they said it's the same as another question (it isn't!). I had to reopen this one. They linked about how to convert using Any, but I am asking about converting `Rc>` into `Rc>` not just `Box` into `&B`. That is the Rc both point to the same thing which will drop correctly when they expire. – Ignatio Mobius Mar 05 '21 at 12:59
  • Also I've been looking at Box which just contains a Unique, which contains a *T. So I assume converting the trait fat pointer to derived pointer is fine. But I would appreciate someone more knowledgeable to confirm if this is true. – Ignatio Mobius Mar 05 '21 at 13:05
  • `Box` and `Box` have different sizes and layouts, so type punning them is wrong (even `transmute` won't work; what you're doing is *more unsafe* than that!) It only appears to work by chance (more or less; the underlying reason is that in a trait object pointer the data pointer is placed first, but you cannot rely on that). – trent Mar 05 '21 at 16:01
  • FWIW, I think the original dupe closure was probably wrong, since `Any` doesn't solve the problem; there's just *no way* to get an `Rc>` out of an `Rc>` without reallocating the `Rc`. Nevertheless, the right thing to do when your question is closed as a duplicate should be to edit the question and make clear that it *isn't* a duplicate, not just to post the same question again. – trent Mar 05 '21 at 16:08

0 Answers0