Skip to content

Instantly share code, notes, and snippets.

@Connicpu
Last active December 20, 2021 11:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Connicpu/2139239f30c633f6450e to your computer and use it in GitHub Desktop.
Save Connicpu/2139239f30c633f6450e to your computer and use it in GitHub Desktop.
Poking a Rust vtable from C++
#![feature(box_syntax)]
pub struct MyThing {
stuff: Vec<i32>,
}
pub trait DoAThing {
fn add(&mut self, item: i32);
fn remove(&mut self) -> i32;
}
impl DoAThing for MyThing {
fn add(&mut self, item: i32) {
self.stuff.push(item);
}
fn remove(&mut self) -> i32 {
match self.stuff.pop() {
Some(value) => value,
None => 0,
}
}
}
#[no_mangle]
pub extern "C" fn new_thing() -> Box<DoAThing> {
box MyThing { stuff: vec![] }
}
#[no_mangle]
pub extern "C" fn free_thing(_: Box<DoAThing>) {
}
#include <Windows.h>
#include <stdint.h>
#include <assert.h>
struct DoAThingVtable
{
void(*destructor)(void *self);
size_t size;
size_t alignment;
void(*add)(void *self, int32_t item);
int32_t(*remove)(void *self);
};
struct BoxDoAThing
{
void *data;
DoAThingVtable *vtable;
};
int main(void)
{
auto lib = LoadLibrary(TEXT("doathing.dll"));
auto new_thing = (BoxDoAThing(*)()) GetProcAddress(lib, "new_thing");
auto free_thing = (void(*)(BoxDoAThing)) GetProcAddress(lib, "free_thing");
auto thing = new_thing();
thing.vtable->add(thing.data, 5);
thing.vtable->add(thing.data, 6);
assert(thing.vtable->remove(thing.data) == 6);
assert(thing.vtable->remove(thing.data) == 5);
assert(thing.vtable->remove(thing.data) == 0);
free_thing(thing);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment