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 poin
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");
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.