Compile-time access to vtable

Transmuting the fat pointer of a trait object gives access its individual parts: the data pointer and the vtable pointer. The actual vtable itself, however, is a compile-time constant. I need to perform some checks and processing on the vtables during compilation or as a post-processing step. Is there a way to obtain the vtable address during compilation or from the resulting elf file? The best I could come up with thus far is generating the assembly output in which you can locate the vtables (rustfilt really helps with this), but I hope there is a more direct method.

Note that the layout of trait objects is not guaranteed so this transmute is likely UB.

There is a Pointer metadata & VTable RFC, which might eventually help?

1 Like

You can use this now on nightly

https://doc.rust-lang.org/nightly/std/raw/struct.TraitObject.html

TraitObject is guaranteed to have the same representation as a trait object. You’ll still have to transmute, but this time it will be sound. There is currently no way to do this on stable.

6 Likes

I know, thanks. However, I'm actually not interested in the layout of the trait object itself, but in the vtable address. I would prefer to process this at compile time, the trait objects do not even exist then. The transmute (eventhough being UB) will only work at run-time.

Thank you, I was pretty sure I did find something that was not UB for this transmute, but I could not find it anymore. However, this still only works at run-time when the trait objects are actually created in memory.

(Note that there is PIE, so it's more like a symbol accessible at link-time)


Here is something I have hacked my way to, which allows to get a specific type's vtable, but requiring that as such type be const inhabitable: Playground

EDIT: Using *const dyn Trait instead of &'static dyn Trait gets rid of the const-inhabitable requirement, as pointed out by @oli-obk

/*
  trait Trait { ... }

  struct Double;
  impl Trait for Double { ... }
*/
const DOUBLE_AS_DYN_TRAIT_VTABLE: *mut () = unsafe {
    const_transmute!([*const dyn Trait => raw::TraitObject](
        ptr::null::<Double>()
    )).vtable
};

I seem to get two different vtable addresses though, but with the same contents (checked with a debugger)

Note that there is no need to use an actual object, you can get a vtable by starting out with a raw pointer:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=45ec73295c7b669841068802141fec38

1 Like

(It would be nice if mem::transmute were made a const fn itself…)

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.