Created
July 18, 2022 03:00
-
-
Save ProgramCrafter/621a8142a71f882cebfa777634976a40 to your computer and use it in GitHub Desktop.
Rust vtables
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(bench_black_box)] | |
use std::ptr::{read, write}; | |
use std::hint::black_box; | |
use std::mem::size_of; | |
use std::any::Any; | |
trait Animal: Any { | |
fn say(&self) -> &'static str; | |
fn name(&self) -> &'static str; | |
} | |
struct Cat; | |
impl Animal for Cat { | |
fn say(&self) -> &'static str {"meow"} | |
fn name(&self) -> &'static str {"cat"} | |
} | |
struct Dog; | |
impl Animal for Dog { | |
fn say(&self) -> &'static str {"bark"} | |
fn name(&self) -> &'static str {"dog"} | |
} | |
fn inspect_fn_ptr(f: usize) -> &'static str { | |
if f == Cat::type_id as usize {return "Cat::type_id";} | |
if f == Dog::type_id as usize {return "Dog::type_id";} | |
if f == Cat::say as usize {return "Cat::say";} | |
if f == Cat::name as usize {return "Cat::name";} | |
if f == Dog::say as usize {return "Dog::say";} | |
if f == Dog::name as usize {return "Dog::name";} | |
"?" | |
} | |
unsafe fn inspect_vtable(reference: &dyn Animal) -> usize { | |
let pr = &reference as *const &dyn Animal as *const usize; | |
println!(); | |
println!("Inspecting metadata of animal {}", reference.name()); | |
println!("Size of reference: {}", size_of::<&dyn Animal>()); | |
const PTR_SIZE: usize = size_of::<usize>(); | |
let meta = read(pr.offset(1)); | |
println!("First {PTR_SIZE} bytes are {}", read(pr)); | |
println!("Vtable {PTR_SIZE} bytes are {}", meta); | |
println!("Cat::say = {}", <Cat as Animal>::say as usize); | |
println!("Dog::say = {}", <Dog as Animal>::say as usize); | |
let pm = meta as *const usize; | |
println!("Vtable[0] = {} [{}::drop_in_place?]", read(pm), reference.name()); | |
println!("Vtable[1] = {} [size?]", read(pm.offset(1))); | |
println!("Vtable[2] = {} [alignment?]", read(pm.offset(2))); | |
println!("Vtable[3] = {} [{}]", read(pm.offset(3)), inspect_fn_ptr(read(pm.offset(3)))); | |
println!("Vtable[4] = {} [{}]", read(pm.offset(4)), inspect_fn_ptr(read(pm.offset(4)))); | |
println!("Vtable[5] = {} [{}]", read(pm.offset(5)), inspect_fn_ptr(read(pm.offset(5)))); | |
println!(); | |
meta | |
} | |
unsafe fn change_vtable(reference: &mut &dyn Animal, meta: usize) { | |
let pr = reference as *mut &dyn Animal as *mut usize; | |
write(pr.offset(1), meta); | |
} | |
fn main() { | |
let cat = Cat; | |
// black boxing just because reference becomes invalid later | |
// and I don't need optimizations inlining Cat at line 83 | |
let mut animal: &dyn Animal = black_box(&cat); | |
unsafe {inspect_vtable(animal)}; | |
println!("{}", animal.say()); | |
unsafe {change_vtable(&mut animal, inspect_vtable(&Dog))}; | |
println!("{}", animal.say()); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Inspecting metadata of animal cat | |
Size of reference: 16 | |
First 8 bytes are 140724672137136 | |
Vtable 8 bytes are 94504553959576 | |
Cat::say = 94504553671552 | |
Dog::say = 94504553671584 | |
Vtable[0] = 94504553671536 [cat::drop_in_place?] | |
Vtable[1] = 0 [size?] | |
Vtable[2] = 1 [alignment?] | |
Vtable[3] = 94504553671424 [Cat::type_id] | |
Vtable[4] = 94504553671552 [Cat::say] | |
Vtable[5] = 94504553671568 [Cat::name] | |
meow | |
Inspecting metadata of animal dog | |
Size of reference: 16 | |
First 8 bytes are 94504553897984 | |
Vtable 8 bytes are 94504553959656 | |
Cat::say = 94504553671552 | |
Dog::say = 94504553671584 | |
Vtable[0] = 94504553671536 [dog::drop_in_place?] | |
Vtable[1] = 0 [size?] | |
Vtable[2] = 1 [alignment?] | |
Vtable[3] = 94504553671440 [Dog::type_id] | |
Vtable[4] = 94504553671584 [Dog::say] | |
Vtable[5] = 94504553671600 [Dog::name] | |
bark |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment