I know there are examples of creating pointers using the LuaJIT FFI, but most of these aren't pointed to existing data. One such example of this is here: How to pass a pointer to LuaJIT ffi to be used as out argument?
One thing that I haven't been able to successfully do is create a pointer to an existing value. In order to have a pointer type as far as I know, I have to know that I want to have a pointer point to it at some point in the future, as in:
local vao = ffi.new("GLuint[1]")
gl.GenVertexArrays(1, vao)
gl.BindVertexArray(vao[0])
Here, I know that glGenVertexArrays needs a pointer to vao
, so I specify it as a GLuint[1]. In C, I would be doing something like the following:
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
Here, I have no idea that I'll be needing a pointer to vao
, so I can just specify it normally.
In other words, is there a way to get the address of, or create a pointer to, an existing value? Do I have to foresee what I'll be doing with the value before I create it?
Thanks!
There's no way to get a pointer to a cdata object in the FFI.
I remember reading in the LuaJIT mailing list that this was done intentionally for some optimizations to work, though I can't find the exact message in the archive.
So far, I haven't had a need for getting the pointer of a cdata object; LuaJIT refers to cdata by reference (similar to tables) and the type[1]
trick works for out parameters.
The reason that you can't get the address of a cdata object is that all cdata objects are garbage collected. If you stop and think that through to its logical conclusion, you'll see this means that they must be allocated on the Lua Heap, rather than the general C heap that malloc
would use. It's highly unsafe to just return pointers into the Lua heap because the garbage collector could come along and move the object at any time.
One consequence of this is that you absolutely should not do what rraallvv suggested, since you're likely to cause a seg-fault.
When you call ffi.new("GLuint[1]")
you allocate an array of GLuint
s on the Lua heap (LuaJIT calls this a 'reference' type) This is ok because when you call into GenVertexArrays()
(1) the GC cannot run, since you're busy executing C-code, (2) GenVertexArrays()
doesn't retain the pointer, so you don't have to worry about a stale pointer being accessed later.
However, LuaJIT's FFI provides enough features that we can build our own allocation contraptions. The following code should (haven't tested this version exactly) allocate data on the C heap and install a default finalizer to free it. If you look up all the FFI functions used, you should get a better sense of things.
local function SafeHeapAlloc(typestr, finalizer)
-- use free as the default finalizer
if not finalizer then finalizer = ffi.C.free end
-- automatically construct the pointer type from the base type
local ptr_typestr = ffi.typeof("$ *", typestr)
-- how many bytes to allocate?
local typesize = ffi.sizeof(typestr)
-- do the allocation and cast the pointer result
local ptr = ffi.cast(ptr_typestr, ffi.C.malloc(typesize))
-- install the finalizer
ffi.gc( ptr, finalizer )
return ptr
end
I was able to do that with a C function that copies the cdata pointer like this
void cdataToPointer(void *cdata, void **pointer) {
*pointer = cdata;
}
// ...
void *mycdata = NULL;
lua_pushlightuserdata(L, &mycdata);
lua_setglobal(L, "__TEMP_USERDATA__");
luaL_dostring(L,
"local ffi = require'ffi'\n"
"ffi.cdef[[\n"
" void cdataToPointer(void *cdata, void **pointer);\n"
"]]\n"
"ffi.C.cdataToPointer(mycdata, __TEMP_USERDATA__)\n");
来源:https://stackoverflow.com/questions/24112779/how-can-i-create-a-pointer-to-existing-data-using-the-luajit-ffi