Rust closure as callback for C bindings receiving garbage value in captured variable - closures

I'm writing Rust wrappers for C bindings so that they look more Rusty. One such C function is this:
void mosquitto_connect_callback_set(
struct mosquitto * mosq,
void (*on_connect)(struct mosquitto *, void *, int)
)
I'm using the below technique to pass a Rust closure as the user data to above binding (void* in the callback) so that the Rust closure will be called when the C callback is invoked.
// Registered callback is called when the broker sends a CONNACK message in response
// to a connection. Will be called even incase of failure. All your sub/pub stuff
// should ideally be done in this callback when connection is successful
pub fn onconnect_callback<F>(&self, callback: F)
where F: Fn(i32)
{
// Convert the rust closure into void* to be used as user_data. This will
// be passed to callback automatically by the library
let cb = &callback as *const _ as *mut libc::c_void;
unsafe {
// Set our closure as user data
bindings::mosquitto_user_data_set(self.mosquitto, cb);
// Register callback
bindings::mosquitto_connect_callback_set(self.mosquitto, Some(onconnect_wrapper::<F>));
}
// Registered callback. user data is our closure
unsafe extern "C" fn onconnect_wrapper<F>(mqtt: *mut bindings::Struct_mosquitto,
closure: *mut libc::c_void,
val: libc::c_int)
where F: Fn(i32)
{
let closure = closure as *mut F;
println!("rc = {:?}", val as i32);
(*closure)(val as i32);
}
}
But the problem is that user data is set using a function instead of directly passing it to the callback set function
// Set our closure as user data
bindings::mosquitto_user_data_set(self.mosquitto, cb);
I think the callback: F closure passed to onconnect_callback might get destroyed by the time the actual C callback is invoked. This might be the reason I'm getting garbage values when capturing a variable.
let i = 100;
client.onconnect_callback(|a: i32|{
println!("i = {:?}", i);
println!("### On connect callback {}###", a)
});
match client.connect("localhost"){
Ok(_) => println!("Connection successful --> {:?}", client),
Err(n) => panic!("Connection error = {:?}", n)
}
OUTPUT:
i = 734146560
### On connect callback 0###
How do I fix this without passing closure as reference?
The full code

Related

Could someone explain how this works: const print = #import("std").debug.print;

How can this const print variable behave like a function?
const print = #import("std").debug.print;
print("hello, world", .{});
I understand you can assign expressions to variables. But this seems to behave like a precompiler macro in c/c++, I wouldn't have guessed that.
Is it because "all variables declared in a comptime expression are implicitly comptime variables" and # makes it a comptime expression, so it is evaluated before compilation, much like a macro would in c?
Could someone elaborate a bit? This seems a very powerful feature.
# does not indicate a comptime expression; rather # prefixes built-in functions in Zig. #import returns a struct that provides access to the declarations made public by the imported file.
The expression #import("std").debug.print evaluates to the print function defined in the standard library file std/debug.zig; it is not the expression that is assigned to print in the posted code, but the function. That is, the posted code works because print in OP code is actually a function. This can be seen by running the code below:
const print = #import("std").debug.print;
pub fn main() void {
print("#TypeOf print: {}\n", .{ #TypeOf(print) });
}
Results:
$ zig run print_type.zig
#TypeOf print: fn(comptime []const u8, anytype) void
Function Assignment
OP has asked for another example of assigning a function that is not imported to an identifier:
const print = #import("std").debug.print;
fn my_function(msg: []const u8) void {
print("{s}\n", .{ msg });
}
const my_function_alias = my_function;
pub fn main() void {
const another_function_alias = my_function;
const yet_another_function_alias = my_function_alias;
my_function("mf");
my_function_alias("mfa");
another_function_alias("afa");
yet_another_function_alias("yafa");
}
Program output:
$ zig run function_assignment.zig
mf
mfa
afa
yafa

How do I pass a stream or writer parameter to a function in Zig?

I'm trying to pass the output stream to a function but can't get it right. This sample code shows a couple of the things I've tried
// Attempts to pass stream or writer to a function
const std = #import("std");
pub fn main() !void {
// #1
try print1(std.io.getStdOut(), "Hello, ");
// #2
try print2(std.io.getStdOut().writer(), "world!");
}
// error: 'File' is not marked 'pub'
pub fn print1(file: std.io.File, str: []const u8) !void
{
try file.writer().print("{s}", .{str});
}
// error: expected type 'type', found 'fn(comptime type, comptime type, comptime anytype) type'
fn print2(writer: std.io.Writer, str: []const u8) !void
{
try writer.print("{s}", .{str});
}
I'm using Zig 0.10.0
The call to std.io.getStdOut() returns a File, but the File type is in the std.fs namespace. Calling std.io.getStdOut().writer() returns a Writer from the std.fs.File namespace. You could also declare the writer parameter with the anytype keyword to get type inference at the time of the function call.
Here is a modified version of OP posted code:
const std = #import("std");
pub fn main() !void {
const stdout = std.io.getStdOut();
const writer = stdout.writer();
// #1
// Pass `stdout` to a function:
try print1(stdout, "Hello, ");
// #2
// Pass a `Writer` to a function:
try print2(writer, "world!\n");
// #3
// Pass a `Writer` to a function:
try print3(writer, "Hello, again!\n");
}
fn print1(file: std.fs.File, str: []const u8) !void {
try file.writer().print("{s}", .{str});
}
// Explicit type annotation for `writer`:
fn print2(writer: std.fs.File.Writer, str: []const u8) !void {
try writer.print("{s}", .{str});
}
// The type of `writer` is inferred when the function is called:
fn print3(writer: anytype, str: []const u8) !void {
try writer.print("{s}", .{str});
}
And a sample run:
$ zig run print_stream.zig
Hello, world!
Hello, again!
io.Writer is a generic data structure. I.e. it's a function that returns a type. You cannot use it as a function argument, but you can:
Use anytype.
Use an alias, like fs.File.Writer.
Use a "proxy" type, like fs.File, on which you'll call writer().
Use full specialization, like io.Writer(fs.File, fs.File.WriteError, fs.File.write).
anytype is required for functions that must accept arbitrary writers. Otherwise, it might be nicer to use an alias or a "proxy" type.

FatalExecutionEngineError on accessing a pointer set with memcpy_s

See update 1 below for my guess as to why the error is happening
I'm trying to develop an application with some C#/WPF and C++. I am having a problem on the C++ side on a part of the code that involves optimizing an object using GNU Scientific Library (GSL) optimization functions. I will avoid including any of the C#/WPF/GSL code in order to keep this question more generic and because the problem is within my C++ code.
For the minimal, complete and verifiable example below, here is what I have. I have a class Foo. And a class Optimizer. An object of class Optimizer is a member of class Foo, so that objects of Foo can optimize themselves when it is required.
The way GSL optimization functions take in external parameters is through a void pointer. I first define a struct Params to hold all the required parameters. Then I define an object of Params and convert it into a void pointer. A copy of this data is made with memcpy_s and a member void pointer optimParamsPtr of Optimizer class points to it so it can access the parameters when the optimizer is called to run later in time. When optimParamsPtr is accessed by CostFn(), I get the following error.
Managed Debugging Assistant 'FatalExecutionEngineError' : 'The runtime
has encountered a fatal error. The address of the error was at
0x6f25e01e, on thread 0x431c. The error code is 0xc0000005. This error
may be a bug in the CLR or in the unsafe or non-verifiable portions of
user code. Common sources of this bug include user marshaling errors
for COM-interop or PInvoke, which may corrupt the stack.'
Just to ensure the validity of the void pointer I made, I call CostFn() at line 81 with the void * pointer passed as an argument to InitOptimizer() and everything works. But in line 85 when the same CostFn() is called with the optimParamsPtr pointing to data copied by memcpy_s, I get the error. So I am guessing something is going wrong with the memcpy_s step. Anyone have any ideas as to what?
#include "pch.h"
#include <iostream>
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace std;
// An optimizer for various kinds of objects
class Optimizer // GSL requires this to be an unmanaged class
{
public:
double InitOptimizer(int ptrID, void *optimParams, size_t optimParamsSize);
void FreeOptimizer();
void * optimParamsPtr;
private:
double cost = 0;
};
ref class Foo // A class whose objects can be optimized
{
private:
int a; // An internal variable that can be changed to optimize the object
Optimizer *fooOptimizer; // Optimizer for a Foo object
public:
Foo(int val) // Constructor
{
a = val;
fooOptimizer = new Optimizer;
}
~Foo()
{
if (fooOptimizer != NULL)
{
delete fooOptimizer;
}
}
void SetA(int val) // Mutator
{
a = val;
}
int GetA() // Accessor
{
return a;
}
double Optimize(int ptrID); // Optimize object
// ptrID is a variable just to change behavior of Optimize() and show what works and what doesn't
};
ref struct Params // Parameters required by the cost function
{
int cost_scaling;
Foo ^ FooObj;
};
double CostFn(void *params) // GSL requires cost function to be of this type and cannot be a member of a class
{
// Cast void * to Params type
GCHandle h = GCHandle::FromIntPtr(IntPtr(params));
Params ^ paramsArg = safe_cast<Params^>(h.Target);
h.Free(); // Deallocate
// Return the cost
int val = paramsArg->FooObj->GetA();
return (double)(paramsArg->cost_scaling * val);
}
double Optimizer::InitOptimizer(int ptrID, void *optimParamsArg, size_t optimParamsSizeArg)
{
optimParamsPtr = ::operator new(optimParamsSizeArg);
memcpy_s(optimParamsPtr, optimParamsSizeArg, optimParamsArg, optimParamsSizeArg);
double ret_val;
// Here is where the GSL stuff would be. But I replace that with a call to CostFn to show the error
if (ptrID == 1)
{
ret_val = CostFn(optimParamsArg); // Works
}
else
{
ret_val = CostFn(optimParamsPtr); // Doesn't work
}
return ret_val;
}
// Release memory used by unmanaged variables in Optimizer
void Optimizer::FreeOptimizer()
{
if (optimParamsPtr != NULL)
{
delete optimParamsPtr;
}
}
double Foo::Optimize(int ptrID)
{
// Create and initialize params object
Params^ paramsArg = gcnew Params;
paramsArg->cost_scaling = 11;
paramsArg->FooObj = this;
// Convert Params type object to void *
void * paramsArgVPtr = GCHandle::ToIntPtr(GCHandle::Alloc(paramsArg)).ToPointer();
size_t paramsArgSize = sizeof(paramsArg); // size of memory block in bytes pointed to by void pointer
double result = 0;
// Initialize optimizer
result = fooOptimizer->InitOptimizer(ptrID, paramsArgVPtr, paramsArgSize);
// Here is where the loop that does the optimization will be. Removed from this example for simplicity.
return result;
}
int main()
{
Foo Foo1(2);
std::cout << Foo1.Optimize(1) << endl; // Use orig void * arg in line 81 and it works
std::cout << Foo1.Optimize(2) << endl; // Use memcpy_s-ed new void * public member of Optimizer in line 85 and it doesn't work
}
Just to reiterate I need to copy the params to a member in the optimizer because the optimizer will run all through the lifetime of the Foo object. So it needs to exist as long as the Optimizer object exist and not just in the scope of Foo::Optimize()
/clr support need to be selected in project properties for the code to compile. Running on an x64 solution platform.
Update 1: While trying to debug this, I got suspicious of the way I get the size of paramsArg at line 109. Looks like I am getting the size of paramsArg as size of int cost_scaling plus size of the memory storing the address to FooObj instead of the size of memory storing FooObj itself. I realized this after stumbling across this answer to another post. I confirmed this by checking the value of paramsArg after adding some new dummy double members to Foo class. As expected the value of paramsArg doesn't change. I suppose this explains why I get the error. A solution would be to write code to correctly calculate the size of a Foo class object and set that to paramsArg instead of using sizeof. But that is turning out to be too complicated and probably another question in itself. For example, how to get size of a ref class object? Anyways hopefully someone will find this helpful.

Using SNMP++ method with callback in .mm file

I am using SNMP++ library in my project and everything works fine. However, there is a method where I need to get callback in my .mm file. Now when I am creating a block and passing it to that function as parameter, it throws an error "No matching member function for call to 'get_bulk'". Here is the piece of code:
void(^callbackFunc)(int,Snmp*,Pdu&,SnmpTarget&,void*);
callbackFunc = ^(int i,Snmp* s,Pdu& p,SnmpTarget& t,void* v) {
};
snmp.get_bulk(pdu, *target, l_repeaters, l_repetitions,callbackFunc);
Also, here is the function signature for "get_bulk" function:
int Snmp::get_bulk(Pdu &pdu, // pdu to use
const SnmpTarget &target, // destination target
const int non_repeaters, // number of non repeaters
const int max_reps, // maximum number of repetitions
const snmp_callback callback,// callback to use
const void * callback_data) // callback data
{
pdu.set_type( sNMP_PDU_GETBULK_ASYNC);
return snmp_engine( pdu, non_repeaters, max_reps, target,
callback, callback_data);
}
What should I pass in 'callback' type?This is the typedef for SNMP_callback:
typedef void (*snmp_callback)(int reason, Snmp *session,
Pdu &pdu, SnmpTarget &target, void *data);
I am stuck on this for the past 4-5 hours now and I can't figure out how to resolve this.
Apple's blocks are not convertible to function pointers, as they also contain data (captured variables, etc.) and a reference counting mechanism. You will need to pass a free function, static C++ class member function, or a C++ non-capturing lambda as the callback.
The lambda is the closest syntactically to a block; only non-capturing lambdas are convertible to a function pointer, however, so you will need to do the capturing "by hand" by passing a pointer to a context struct or similar through the void* callback_data argument which presumably is passed through to the callback as void* data.
The lambda will look something like this:
snmp_callback callback =
[](int reason, Snmp *session, Pdu &pdu, SnmpTarget &target, void *data)
{
// context_struct_type* context = static_cast<context_struct_type*>(data);
};

Assign function/method to variable in Dart

Does Dart support the concept of variable functions/methods? So to call a method by its name stored in a variable.
For example in PHP this can be done not only for methods:
// With functions...
function foo()
{
echo 'Running foo...';
}
$function = 'foo';
$function();
// With classes...
public static function factory($view)
{
$class = 'View_' . ucfirst($view);
return new $class();
}
I did not found it in the language tour or API. Are others ways to do something like this?
To store the name of a function in variable and call it later you will have to wait until reflection arrives in Dart (or get creative with noSuchMethod). You can however store functions directly in variables like in JavaScript
main() {
var f = (String s) => print(s);
f("hello world");
}
and even inline them, which come in handy if you are doing recusion:
main() {
g(int i) {
if(i > 0) {
print("$i is larger than zero");
g(i-1);
} else {
print("zero or negative");
}
}
g(10);
}
The functions stored can then be passed around to other functions
main() {
var function;
function = (String s) => print(s);
doWork(function);
}
doWork(f(String s)) {
f("hello world");
}
I may not be the best explainer but you may consider this example to have a wider scope of the assigning functions to a variable and also using a closure function as a parameter of a function.
void main() {
// a closure function assigned to a variable.
var fun = (int) => (int * 2);
// a variable which is assigned with the function which is written below
var newFuncResult = newFunc(9, fun);
print(x); // Output: 27
}
//Below is a function with two parameter (1st one as int) (2nd as a closure function)
int newFunc(int a, fun) {
int x = a;
int y = fun(x);
return x + y;
}

Resources