Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FFI typedefs of functions (not function pointers) #676

Closed
fffonion opened this issue Mar 25, 2021 · 1 comment
Closed

FFI typedefs of functions (not function pointers) #676

fffonion opened this issue Mar 25, 2021 · 1 comment
Labels

Comments

@fffonion
Copy link

The following example exhausted the FFI ctypes table:

local ffi = require("ffi")

ffi.cdef ([[
typedef void (cb)();
]])

for i=1,40000 do
    local pok, pp = pcall(ffi.cast, "cb*", function() end)
    if not pok then
        print(pp, " at ", i)
        break
    end
    pp:free()
end

ouputs table overflow at 32539

Although there're tons of solutions including using ffi.typeof("cb*") to reuse the type,
define it with typedef void (*cb)(); and then use as ffi.cast("cb", function() end).
It may still be a surprise to users as ffi.cast("cb*", function() end) implictly creates
one CT_PTR type and one CT_FUNC type each time it's called.

Consider the case for example a struct, there's no issue with the following code:

local ffi = require("ffi")

ffi.cdef ([[
typedef struct P {
} P;
]])

for i=1,40000 do
    -- parses as a PTR and no new ctypes created
    local pok = pcall(ffi.new, "P*")
    if not pok then
        print(pp, " at ", i)
        break
    end
end

From the code https://github.com/LuaJIT/LuaJIT/blob/v2.1/src/lj_cparse.c#L886 I can see when parser parses a
function, it will always create a new ctype, no matter the context is ffi.cdef or ffi.new/cast. My question
is that is this by-purpose or is a bug?

@fffonion fffonion changed the title Duplicate ctype created with pointer callback cdef Duplicate ctype created with pointer callback in FFI Mar 25, 2021
@MikePall MikePall changed the title Duplicate ctype created with pointer callback in FFI FFI typedefs of functions (not function pointers) Mar 25, 2021
@MikePall
Copy link
Member

One should always use C function pointers for the callback cast.

A typedef for a function (and not a function pointer) is an awkward corner of the C spec. IMHO there's no good reason to use them anywhere. Functions are not considered values in C, only pointers to functions are.

Following the C spec, every use of such a typedef creates a new function (and C compilers agree):

typedef int (func_t)(int);
func_t f1;
func_t f2;

is equivalent to

int f1(int);
int f2(int);

It's just that you can't dynamically create functions in C, which makes this less apparent.

So, yes, your FFI cast creates a new (anonymous) C function on every invocation. Also, the code in cp_decl_intern technically couldn't intern the function, because the ->next field is already used by the by-name-lookup hash table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants