How do I implement callbacks to self through FFI in Rust? [duplicate] - callback
Okay, I'm trying to achieve the following:
C calls into rust
rust calls back into c and registers a callback on a user defined trait object
c calls into rust with the context
rust calls the callback on the context (trait object)
I've been playing around with it quite a bit. I got quite far, but still not quite there.
The C bit:
#include <dlfcn.h>
#include <stdio.h>
void *global_ctx;
void c_function(void* ctx) {
printf("Called c_function\n");
global_ctx = ctx;
}
int main(void) {
void *thing = dlopen("thing/target/debug/libthing.dylib", RTLD_NOW | RTLD_GLOBAL);
if (!thing) {
printf("error: %s\n", dlerror());
return 1;
}
void (*rust_function)(void) = dlsym(thing, "rust_function");
void (*rust_cb)(void*) = dlsym(thing, "rust_cb");
printf("rust_function = %p\n", rust_function);
rust_function();
rust_cb(global_ctx);
}
The rust bit:
extern crate libc;
pub trait Foo {
fn callback(&self);
}
extern {
fn c_function(context: *mut libc::c_void);
}
pub struct MyFoo;
impl Foo for MyFoo {
fn callback(&self) {
println!("callback on trait");
}
}
#[no_mangle]
pub extern fn rust_cb(context: *mut Foo) {
unsafe {
let cb:Box<Foo> = Box::from_raw(context);
cb.callback();
}
}
#[no_mangle]
pub extern fn rust_function() {
println!("Called rust_function");
let tmp = Box::new(MyFoo);
unsafe {
c_function(Box::into_raw(tmp) as *const Foo as *mut libc::c_void);
}
}
The issue:
My program segfaults when I try to call "callback" on the trait object in "rust_cb"
One Solution:
- Change the function signature of "rust_cb" to
pub extern fn rust_cb(context: *mut MyFoo)
but that's not what I want, as I'm trying to create a safe wrapper that only knows the trait of the listener
Any help appreciated
PS: my assumption is that it segfaults, because the compiler doesn't know the offset of callback on the trait Foo, it needs the actual object to determine where it is. but then i have no idea how to work around that
So, if you need to represent the Foo as a void *, you can use this:
extern crate libc;
pub trait Foo {
fn callback(&self);
}
extern {
fn c_function(context: *mut libc::c_void);
}
pub struct MyFoo;
impl Foo for MyFoo {
fn callback(&self) {
println!("callback on trait");
}
}
#[no_mangle]
pub extern fn rust_cb(context: *mut Box<Foo>) {
unsafe {
let cb: Box<Box<Foo>> = Box::from_raw(context);
cb.callback();
}
}
#[no_mangle]
pub extern fn rust_function() {
println!("Called rust_function");
let tmp: Box<Box<Foo>> = Box::new(Box::new(MyFoo));
unsafe {
c_function(Box::into_raw(tmp) as *mut Box<Foo> as *mut libc::c_void);
}
}
I think you may be misunderstanding what a trait object is. A trait object is a type that is the size of two pointers (so, 128 bits on a 64-bit system). In this example, Foo is not a trait object, it is a dynamically sized type (i.e. a type which has a variable size, such as str). Box<Foo> is a trait object. Box<Box<Foo>> is neither a trait object or a dynamically sized type, it is a type that has the same size as a pointer, which is why we need to use it here since we want to convert it into a void *.
I call it "leaking" because when you call Box::into_raw, you are leaking the memory of whatever is in the box, which means that that you are responsible for making sure the destructor (the Drop implementation) gets called.
Rust trait objects such as Box<Foo> are double the size of a normal pointer, so you can't use void * to represent them. See std::raw::TraitObject for more information. Here is a working version of your code:
program.c:
#include <dlfcn.h>
#include <stdio.h>
struct rs_trait_obj {
void *data;
void *vtable;
};
struct rs_trait_obj global_ctx;
void c_function(struct rs_trait_obj ctx) {
printf("Called c_function\n");
global_ctx = ctx;
}
int main(void) {
void *thing = dlopen("thing/target/debug/libthing.dylib", RTLD_NOW | RTLD_GLOBAL);
if (!thing) {
printf("error: %s\n", dlerror());
return 1;
}
void (*rust_function)(void) = dlsym(thing, "rust_function");
void (*rust_cb)(struct rs_trait_obj) = dlsym(thing, "rust_cb");
printf("rust_function = %p\n", rust_function);
rust_function();
rust_cb(global_ctx);
}
lib.rs:
#![feature(raw)]
extern crate libc;
use std::raw::TraitObject;
use std::mem;
pub trait Foo {
fn callback(&self);
}
extern {
fn c_function(context: TraitObject);
}
pub struct MyFoo;
impl Foo for MyFoo {
fn callback(&self) {
println!("callback on trait");
}
}
#[no_mangle]
pub extern fn rust_cb(context: TraitObject) {
unsafe {
let cb: Box<Foo> = mem::transmute(context);
cb.callback();
}
}
#[no_mangle]
pub extern fn rust_function() {
println!("Called rust_function");
let tmp: Box<Foo> = Box::new(MyFoo);
unsafe {
c_function(mem::transmute(tmp));
}
}
This will only work on nightly rustc (because of the #![feature(raw)]) and will also give a warning because TraitObject isn't FFI-safe. If you want something that will work on stable, you can define some struct of an appropriate size like this and use it instead of TraitObject:
#[repr(C)]
struct FFITraitObject {
data: usize,
vtable: usize,
}
Another option, of course, would just be to use Box<Foo> in place of TraitObject, but then you would still get a warning:
extern crate libc;
pub trait Foo {
fn callback(&self);
}
extern {
fn c_function(context: Box<Foo>);
}
pub struct MyFoo;
impl Foo for MyFoo {
fn callback(&self) {
println!("callback on trait");
}
}
#[no_mangle]
pub extern fn rust_cb(context: Box<Foo>) {
context.callback();
}
#[no_mangle]
pub extern fn rust_function() {
println!("Called rust_function");
let tmp: Box<Foo> = Box::new(MyFoo);
unsafe {
c_function(tmp);
}
}
If you really want to use a void *, you could consider leaking the TraitObject as well as the MyFoo and use two levels of indirection.
Related
c++/cli unmanaged library into managed code
I have the following code in c++/cli ` public ref class Form1 : public System::Windows::Forms::Form { public: Form1(void) { InitializeComponent(); // //TODO: Konstruktorcode hier hinzufügen. // delegate int fooProc(UInt16); } ... public: void goTest(int x) { // declared in header fooProc^ managed = gcnew fooProc(this, &Form1::foo); IntPtr stubPointer = Marshal::GetFunctionPointerForDelegate(managed); slave[x].module = static_cast<int(*)(unsigned short)>(stubPointer.ToPointer()); ... } } public: int foo(unsigned short test) { Form1::label1->Text = "Hello success !"; ... return 1; // seems to not return to library function ( Run-Time Check Failure #0 - The value of ESP was not properly saved ...) } ` then in a static library with native code there is a function which calls the method 'foo' thru the pointer slave[x].module as following: int nativefoo(...) { ... anyStruct[x].module(x); // struct defined in header ... return 0; } The code crashes in method on return. Probably mismatch in calling conventions. I have no idea how to solve this issue. I only tried to alter and match the calling conventions. From __clrcall to __cdecl but no affect.
what is the correct syntax function pointer list with class member?
I have a list of function pointers, the non-class member compiles without errors, but the class member compiles with errors: error: cannot convert 'void (CVdmConfig::)()' to 'fp {aka void ()()}' in initialization CVdmConfig::writeConfig is a void function. typedef void (*fp)(); fp fpList[] = {&valvesCalib,&CVdmConfig::writeConfig} ; What do I wrong ? best regards Werner
Without seeing the rest of your code, there is not much I can debug, but here is an example that works: #include <iostream> using namespace std; void valvesCalib() { cout << "inside function\n"; } class CVdmConfig { public: static void writeConfig() { cout << "inside method\n"; } }; typedef void (*fp)(); fp fpList[] = { &valvesCalib, &CVdmConfig::writeConfig }; int main() { for (auto f: fpList) { f(); } return 0; } /* Output: inside function inside method Program finished with exit code 0 */
The problem was the missing static definition in the member function. But this leads into other problems with variables in the class. So I use a wrapper for this.
In Rust, when assertion fails hop into debugger
A simple library that has been very convenient, indispensable even, in C# is namespace SharedLibraries.Verification { public static class Verify { // conditions that must be satisfied in order to use a module go here public static void Require(bool B) { if (B) return; System.Diagnostics.Debugger.Break(); } // things that should be provably true if the Require(s) of a module are met public static void Assert(bool B) { if (B) return; System.Diagnostics.Debugger.Break(); } public static void AssertFail() { System.Diagnostics.Debugger.Break(); } }} namespace SharedLibraries.VerificationOff { public static class Verify { [System.Diagnostics.Conditional("DoNotEverTurnThisOn")] public static void Require(bool B) {} [System.Diagnostics.Conditional("DoNotEverTurnThisOn")] public static void Assert(bool B) {} [System.Diagnostics.Conditional("DoNotEverTurnThisOn")] public static void AssertFail() {} }} If a requirement or assertion fails, it pops me into the debugger. When I want to turn it off, I just change the include command from Verification to VerificationOff. It won't even compute "B" when it is turned off so there is no overhead. I have been trying all kinds of different things to try to make a Rust/VSCode library to do the same thing. Here is what I have so far: pub mod on { pub fn require<Predicate: FnOnce() -> bool>(check : Predicate) { if cfg!(debug_assertions) { if !check() { unsafe { println!("before debug break"); winapi::um::debugapi::DebugBreak(); println!("after debug break"); } } } } pub fn assert<Predicate: FnOnce() -> bool>(check : Predicate) { if cfg!(debug_assertions) { if !check() { unsafe { winapi::um::debugapi::DebugBreak(); } } } } } pub mod off { pub fn require<Predicate: FnOnce() -> bool>(_check : Predicate) {} pub fn assert <Predicate: FnOnce() -> bool>(_check : Predicate) {} } This works at least when the above code is in the same crate as the program that is executed. But when it is included from a standalone crate using "extern crate verifier" (or whatever name) then whenever an assertion fails the program just crashes and the debugger closes down. And it crashes exactly on the winapi call. The debugger vscode is using is cppvsdbg for windows. I'm looking for help to make this work. Maybe converting to macros or using a different command to get the debuggers attention. I'm very fresh with rust so please be explicit.
Swift: how to understand dynamic method dispatching in init method?
I find that the dynamic method dispatching in init method of Swift is different from which in C++, can anyone explain why? This is the demo code and its output: In Swift: class Object { init() { a() } func a() { print("Object") } } class SubObject: Object { override init() { } override func a() { print("SubObject") } } let a = SubObject() // output: SubObject In C++: class Object { public: Object() { a(); } virtual void a() { std::cout << "Object" << std::endl; } }; class SubObject: public Object { public: SubObject() { } virtual void a() { std::cout << "SubObject" << std::endl; } }; int main(int argc, const char * argv[]) { SubObject s; return 0; } // output: Object As you can see, these code above write in Swift and C++ are nearly the same, but their output is quite different, while Swift seems that it finds the override method and called the derived one, the C++ still called the super's. Here at LearnCpp, it says: Do not call virtual functions from constructors or destructors Here’s another gotcha that often catches unsuspecting new programmers. You should not call virtual functions from constructors or destructors. Why? Remember that when a Derived class is created, the Base portion is constructed first. If you were to call a virtual function from the Base constructor, and Derived portion of the class hadn’t even been created yet, it would be unable to call the Derived version of the function because there’s no Derived object for the Derived function to work on. In C++, it will call the Base version instead. A similar issue exists for destructors. If you call a virtual function in a Base class destructor, it will always resolve to the Base class version of the function, because the Derived portion of the class will already have been destroyed.
What are function typedefs / function-type aliases in Dart?
I have read the description, and I understand that it is a function-type alias. A typedef, or function-type alias, gives a function type a name that you can use when declaring fields and return types. A typedef retains type information when a function type is assigned to a variable. http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#kix.yyd520hand9j But how do I use it? Why declaring fields with a function-type? When do I use it? What problem does it solve? I think I need one or two real code examples.
A common usage pattern of typedef in Dart is defining a callback interface. For example: typedef void LoggerOutputFunction(String msg); class Logger { LoggerOutputFunction out; Logger() { out = print; } void log(String msg) { out(msg); } } void timestampLoggerOutputFunction(String msg) { String timeStamp = new Date.now().toString(); print('${timeStamp}: $msg'); } void main() { Logger l = new Logger(); l.log('Hello World'); l.out = timestampLoggerOutputFunction; l.log('Hello World'); } Running the above sample yields the following output: Hello World 2012-09-22 10:19:15.139: Hello World The typedef line says that LoggerOutputFunction takes a String parameter and returns void. timestampLoggerOutputFunction matches that definition and thus can be assigned to the out field. Let me know if you need another example.
Dart 1.24 introduces a new typedef syntax to also support generic functions. The previous syntax is still supported. typedef F = List<T> Function<T>(T); For more details see https://github.com/dart-lang/sdk/blob/master/docs/language/informal/generic-function-type-alias.md Function types can also be specified inline void foo<T, S>(T Function(int, S) aFunction) {...} See also https://www.dartlang.org/guides/language/language-tour#typedefs
typedef LoggerOutputFunction = void Function(String msg); this looks much more clear than previous version
Just slightly modified answer, according to the latest typedef syntax, The example could be updated to: typedef LoggerOutputFunction = void Function(String msg); class Logger { LoggerOutputFunction out; Logger() { out = print; } void log(String msg) { out(msg); } } void timestampLoggerOutputFunction(String msg) { String timeStamp = new Date.now().toString(); print('${timeStamp}: $msg'); } void main() { Logger l = new Logger(); l.log('Hello World'); l.out = timestampLoggerOutputFunction; l.log('Hello World'); }
Typedef in Dart is used to create a user-defined function (alias) for other application functions, Syntax: typedef function_name (parameters); With the help of a typedef, we can also assign a variable to a function. Syntax:typedef variable_name = function_name; After assigning the variable, if we have to invoke it then we go as: Syntax: variable_name(parameters); Example: // Defining alias name typedef MainFunction(int a, int b); functionOne(int a, int b) { print("This is FunctionOne"); print("$a and $b are lucky numbers !!"); } functionTwo(int a, int b) { print("This is FunctionTwo"); print("$a + $b is equal to ${a + b}."); } // Main Function void main() { // use alias MainFunction number = functionOne; number(1, 2); number = functionTwo; // Calling number number(3, 4); } Output: This is FunctionOne 1 and 2 are lucky numbers !! This is FunctionTwo 3 + 4 is equal to 7
Since dart version 2.13 you can use typedef not only with functions but with every object you want. Eg this code is now perfectly valid: typedef IntList = List<int>; IntList il = [1, 2, 3]; For more details see updated info: https://dart.dev/guides/language/language-tour#typedefs
https://www.tutorialspoint.com/dart_programming/dart_programming_typedef.htm typedef ManyOperation(int firstNo , int secondNo); //function signature Add(int firstNo,int second){ print("Add result is ${firstNo+second}"); } Subtract(int firstNo,int second){ print("Subtract result is ${firstNo-second}"); } Divide(int firstNo,int second){ print("Divide result is ${firstNo/second}"); } Calculator(int a,int b ,ManyOperation oper){ print("Inside calculator"); oper(a,b); } main(){ Calculator(5,5,Add); Calculator(5,5,Subtract); Calculator(5,5,Divide); }