q66 / cffi-lua

A portable C FFI for Lua 5.1+
MIT License
176 stars 24 forks source link

Support redefining nested anonymous struct within anonymous struct #11

Closed vsergeev closed 3 years ago

vsergeev commented 3 years ago
local ffi = jit and require('ffi') or require('cffi')

ffi.cdef[[
    typedef struct {
        struct {
            uint32_t a;
        } inner1;
    } foo_t;

    typedef struct {
        struct {
            uint32_t b;
        } inner2;
    } bar_t;
]] -- expected: no error, get: input:1: 'struct 0' redefined

print(ffi.new("foo_t")) --> cdata<struct 95>: 0x40e88a78
print(ffi.new("bar_t")) --> cdata<struct 100>: 0x40e88b40

cffi-lua raises an error when redefining a nested anonymous struct within an anonymous struct. This is problematic in a codebase where two typedef anonymous structures happen to share a nested anonymous structure by sheer coincidence.

Note, however, redefinition of the nested anonymous structure is OK if the parent structure is named:

ffi.cdef[[
    struct foo {
        struct {
            uint32_t a;
        } inner1;
    };

    struct bar {
        struct {
            uint32_t b;
        } inner2;
    };
]] 
q66 commented 3 years ago

the problem here is slightly different than you think it is; note how you don't need bar_t definition at all to raise the same error

cffi never takes contents of anon structs into account when choosing a name for them, and it never considers contents for redefinitions (only name); the problem here is that when foo_t is anonymous, and its inner struct is anonymous, by the time the inner struct is parsed the outer struct is not committed into the storage yet, and the name for anonymous structs is chosen like "take the number of structs already in storage, and use that". Which means, both of those structures get named struct 0.

vsergeev commented 3 years ago

Ah, OK, I see. Yeah, I was able to simplify the test case to the first definition as you said:

ffi.cdef[[
    typedef struct {
        struct {
            uint32_t a;
        } inner1;
    } foo_t;
]] -- expected: no error, get: input:1: 'struct 0' redefined