I've stumbled upon a problem in Lua. I am using a library to bind C++ classes to Lua but the problem seems to be in Lua and not related to the library.
Steps to reproduce the crash:
Expose a C++ class to Lua as userdata and bind a function to a metamethod like __tostring.
In Lua create an instance of the class.
Call getmetatable with the instance as parameter.
Now pass the returned metatable to another C function that interacts with metafields. Like the function print calls luaL_tolstring which calls the metafield __tostring.
Lua crashes trying to call the class metamethod.
What causes the crash:
A table and not a userdata is passed to for example luaL_tolstring
luaL_tolstring calls __tostring metamethod.
The proxy function bound to __tostring is invoked in LuaBridge
LuaBridge crashes because it received a table and not the valid userdata holding a pointer to the class.
Example using the library LuaBridge
// Some example class with a tostring method.
class ExampleClass
{
public:
ExampleClass() :
a(0), b(0), c(0)
{
}
string tostring() const
{
return "whatever";
}
int a, b, c;
};
lua_State* L = luaL_newstate();
luaL_openlibs(L);
// Expose example class and add a __tostring metamethod
luabridge::getGlobalNamespace(L)
.beginClass<ExampleClass>("ExampleClass")
.addConstructor<void(*) ()>()
.addFunction("__tostring", &ExampleClass::tostring)
.endClass()
;
// Create an instance of the example class.
// Call getmetatable on the instance and pass it to print.
luaL_dostring(L, "local t = ExampleClass(); print(getmetatable(t));");
lua_close(L);
Callstack
main.exe!luabridge::detail::Userdata::getPointer() Line 46 C++
main.exe!luabridge::detail::Userdata::get<ExampleClass>(lua_State * L, int index, bool canBeConst) Line 252 C++
main.exe!luabridge::detail::CFunc::CallConstMember<std::string (__cdecl ExampleClass::*)(void)const>::f(lua_State * L) Line 290 C++
main.exe!precallC(lua_State * L, StackValue * func, int nresults, int(*)(lua_State *) f) Line 506 C
main.exe!luaD_precall(lua_State * L, StackValue * func, int nresults) Line 570 C
main.exe!ccall(lua_State * L, StackValue * func, int nResults, int inc) Line 607 C
main.exe!luaD_callnoyield(lua_State * L, StackValue * func, int nResults) Line 628 C
main.exe!lua_callk(lua_State * L, int nargs, int nresults, __int64 ctx, int(*)(lua_State *, int, __int64) k) Line 1024 C
main.exe!luaL_callmeta(lua_State * L, int obj, const char * event) Line 867 C
main.exe!luaL_tolstring(lua_State * L, int idx, unsigned __int64 * len) Line 885 C
main.exe!luaB_print(lua_State * L) Line 29 C
My question is why does Lua invoke the bound C function of a userdata without passing a valid userdata but rather the metatable.
Related
This question already has answers here:
How can I pass a C++ lambda to a C-callback that expects a function pointer and a context?
(4 answers)
Closed 2 years ago.
I am wrapping around a C function from freeRTOS that creates a task and takes its arguments with void pointer in C++. The function looks a little bit like this:
void createTask(TaskFunction_t taskCode, void * args);
So to my understanding to pass 2 arguments to the task I would need to create a struct, cast its address to void*, pass it and then cast it back to the original state like so:
struct Params
{
const int a;
const double b;
};
static void task(void * args)
{
auto params = *static_cast<Params*>(args);
// do something with params.a and params.b
}
int main()
{
Params params{1, 2.2};
createTask(task, static_cast<void*>(¶ms));
}
What would be preferred way of wrapping this function so that I could pass a variable number of arguments of variable types? Should I just leave void * args as an argument or is there something that could be done with templates or maybe tuples to simplify this process a little bit.
In C++11 onwards, you can use something like
static void call_task(void *args) {
auto& f = *static_cast<std::function<void()>*>(args);
f();
}
// note: need this to stay alive!
std::function<void()> f = [&](){
// Any arguments you like here
do_whatever(1, 2, 3)
};
CreateTask(call_task, static_cast<void*>(&f));
You need to ensure the lifetime of f is longer than that of the task (just as you would for your Params object).
You can actually avoid std::function altogether, as:
template<typename Func>
void call_func(void *args) {
auto& f = *static_cast<Func*>(args);
f();
}
template<typename Func>
void wrapped_create_task(Func& func) {
CreateTask(call_func<Func>, static_cast<void*>(&func));
}
// you can still use `std::function` here, but you don't have to.
auto f = [&](){
// Any arguments you like here
do_whatever(1, 2, 3)
};
// this works on any object that implements `operator ()`
wrapped_create_task(f)
Again, it's really important that f remains alive for the duration of its execution. You can't put it on a stack that dies before the task does.
I'm using a C library where the user is supposed to register a int (*functionPtr)(int,int); callback.
Then, some file is processed, and during the file processing the user receives callback with the previously given function, up to thousands for a single file processing.
My question is, how to manage state for this kind of worflow?
For instance I'd like to count how many times the callback was called. The only way I'm thinking of doing this is :
int c = 0; //global variable
int callback(int i, int j) {
++c;
}
Which is basically not very pretty and forces me to manage global variables.
Is there a way to do this effeciently in C++ ? In my case I do not have access to C++11
The standard way is to support a context pointer:
void myAPI(void (*f)(void *, int, int), void *context) {
...
// Call the callback passing the provided context
f(context, x, y);
...
}
The users can then recover custom data from the context if needed... for example
void inc_counter(void *context, int x, int y) {
*((int *)context) += 1;
}
void foo() {
int count = 0;
myAPI(inc_counter, &count);
}
In other words the idea is to add an opaque void * parameter to the callback interface and also a void * value to pass in that parameter when invoking the function.
This doesn't add any coupling but works around the problem that C has no closures.
I've closed-source C++ library, which provides header files with code equivalent to:
class CSomething
{
public:
void getParams( unsigned char & u8OutParamOne,
unsigned char & u8OutParamTwo ) const;
private:
unsigned char u8OutParamOne_,
unsigned char u8OutParamTwo_,
};
I'm trying to expose that to Python, my wrapper code is something like this:
BOOST_PYTHON_MODULE(MySomething)
{
class_<CSomething>("CSomething", init<>())
.def("getParams", &CSomething::getParams,(args("one", "two")))
}
Now I'm trying to use that in Python, which fails horribly:
one, two = 0, 0
CSomething.getParams(one, two)
Which results in:
ArgumentError: Python argument types in
CSomething.getParams(CSomething, int, int)
did not match C++ signature:
getParams(CSomething {lvalue}, unsigned char {lvalue} one, unsigned char {lvalue} two)
What do I need to change either in the Boost.Python wrapper code or Python code to make it work? How do I add some Boost.Python magic to automatically cast PyInt to unsigned char and vice-versa?
Boost.Python is complaining about a missing lvalue parameter, a concept which does not exist in Python:
def f(x):
x = 1
y = 2
f(y)
print(y) # Prints 2
The x paramter of the f function is not a C++-like reference. In C++ the output is different:
void f(int &x) {
x = 1;
}
void main() {
int y = 2;
f(y);
cout << y << endl; // Prints 1.
}
You have a few choices here:
a) Wrap the CSomething.getParams function to return a tuple of the new parameters values:
one, two = 0, 0
one, two = CSomething.getParams(one, two)
print(one, two)
b) Wrap the CSomething.getParams function to accept a class instance as parameter:
class GPParameter:
def __init__(self, one, two):
self.one = one
self.two = two
p = GPParameter(0, 0)
CSomething.getParams(p)
print(p.one, p.two)
How to call a void *function(...) from Fortran?
I am currently trying to call a few C functions from Fortran. I have done so before, but I have called only my own functions. For example, to call:
void add(int *csum, int *ca, int *cb) { *csum = *ca + *cb; }
from Fortran, I have used:
INTEGER :: fsum, fa, fb
CALL add(fsum, fa, fb)
This works fine. Now I have a couple of functions roughly like:
void *create_obj(void);
void use_obj(void *obj);
void free_obj(void *obj);
or even:
struct private_struct; /* defined somewhere else */
struct private_struct *create_p(void);
void use_p(struct private_struct *p);
void free_f(struct private_struct *p);
where the struct is private, i.e., I have no knowledge of its members.
Question: How can I get the return values into Fortran? I do not really need to access them, but I must store them somehow during their create...use...destroy lifecycle.
You can create the object in C, pass a pointer to it to Fortran, then pass that pointer to C routines. Finally, call a C routine to free the memory. The ISO C Binding provides the Fortran type C_PTR.
Instead of returning a pointer to the object you can keep it in an array (or other container) inside the C library and return and index into the array (or whatever it fits your container).
int create_obj(); // returns the obj_id
void use_obj(int *obj_id);
void free_obj(int *obj_id);
You will have to keep count of what elements of the array are being used. Something like
struct Entry {
bool used;
struct Obj value;
}
Entry objects[100];
CreateEntity is a C function I bound to Lua in my project. It takes an entity class name string as first argument, and any number of additional arguments which should get passed to the constructor of the chosen entity.
For example, if CreateEntity was a normal Lua function I could do it this way:
function CreateEntity( class, ... )
-- (choose a constructor function based on class)
args = {...}
-- (store args somewhere for whatever reason)
TheConstructor( ... )
end
But how can I do this with a C Lua function?
The C function lua_gettop will return how many parameters were passed to your C function. You must either read these all from the stack and store them in a C data structure, or place them in the Lua registry (see Registry and luaL_ref) and store references to them for later use. The example program below uses the registry approach.
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include <stdio.h>
#include <stdlib.h>
/* this function prints the name and extra variables as a demonstration */
static void
TheConstructor(lua_State *L, const char *name, int *registry, int n)
{
int i;
puts(name);
for (i = 0; i < n; ++i) {
lua_rawgeti(L, LUA_REGISTRYINDEX, registry[i]);
puts(lua_tostring(L, -1));
}
free(registry);
}
static int
CreateEntity(lua_State *L)
{
const char *NAME = luaL_checkstring(L, 1);
int *registry;
int i, n;
/* remove the name parameter from the stack */
lua_remove(L, 1);
/* check how many arguments are left */
n = lua_gettop(L);
/* create an array of registry entries */
registry = calloc(n, sizeof (int));
for (i = n; i > 0; --i)
registry[i-1] = luaL_ref(L, LUA_REGISTRYINDEX);
TheContructor(L, NAME, registry, n);
return 0;
}
int
main(int argc, char **argv[])
{
const char TEST_CHUNK[] =
"CreateEntity('foo', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)";
lua_State *L;
L = luaL_newstate();
lua_register(L, "CreateEntity", CreateEntity);
luaL_dostring(L, TEST_CHUNK);
lua_close(L);
return EXIT_SUCCESS;
}
args = {...}
-- (store args somewhere for whatever reason)
The arguments of the call are on the Lua stack and you can do with them as you please: put them in a structure of your own (std::vector<boost::any> or something like that) or store individual arguments in the Lua registry or create a Lua table with the arguments and store that in the registry instead. What suits you better?
TheConstructor( ... )
I'm fairly convinced this part is not possible in C++ the way it is in Lua. C++ requires the number of parameters you pass to a function to be known at compile time.
It's a major inconvenience to try and do those things in C++. Maybe be betters solution will come if you tell us why do you want your CreateEntity function to be on the C++ side instead of Lua.