Error:wrong size for struct field

82 views
Skip to first unread message

Yang Liu

unread,
Jul 20, 2016, 4:37:10 AM7/20/16
to python-cffi
hi,
I wrote a simple script that include some netlink structs and had a problem



this is  build_nl.py:

from cffi import FFI

ffibuilder = FFI()

header = """
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h> /* for sa_family_t */
#include <linux/inet_diag.h>
#include <linux/netlink.h>
"""

struct = """
typedef struct {
    struct nlmsghdr nlh;
    struct inet_diag_req diag_req;
}nlreq_t;

/* Creates a new netlink request. */
nlreq_t *nlreq_create();
/* Destroys a  netlink request */
void nlreq_destroy(nlreq_t *req);
"""

ffibuilder.set_source("_netlink", header + struct + """
    nlreq_t *nlreq_create() {
       nlreq_t *req = malloc(sizeof(nlreq_t));

        // set netlink message header
        req->nlh.nlmsg_len    = sizeof(nlreq_t);
        req->nlh.nlmsg_type   = TCPDIAG_GETSOCK;
        req->nlh.nlmsg_flags  = NLM_F_REQUEST|NLM_F_DUMP;
        req->nlh.nlmsg_seq    = 1;

        // set payload
        req->diag_req.idiag_family  = AF_INET;
        req->diag_req.idiag_states  = (1 << 10);  /* TCP_LISTEN */
        req->diag_req.id.idiag_cookie[0] = INET_DIAG_NOCOOKIE;  /* -1 */
        req->diag_req.id.idiag_cookie[1] = INET_DIAG_NOCOOKIE;
        return req;
    };

    void nlreq_destroy(nlreq_t *req) {
        if(&req->nlh)
                        free(&req->nlh);
        if(&req->diag_req)
                        free(&req->diag_req);
        free(req);
    };
""")

ffibuilder.cdef(struct)

if __name__ == "__main__":
    ffibuilder.compile(verbose=True)



and this is nl.py:

from _netlink import ffi, lib

nlreq = ffi.new("nlreq_t *")
print nlreq.nlh


when I run python nl.py I got this error:

ffi.error: nlreq_t: wrong size for field 'nlh' (cdef says -1, but C compiler says 16). fix it or use "...;" in the cdef for nlreq_t to make it flexible

I am not familiar with cffi, could someone explain for "cdef says -1",why sizeof nlsmghr is -1。


Armin Rigo

unread,
Jul 31, 2016, 8:38:38 AM7/31/16
to pytho...@googlegroups.com
Hi,

On 20 July 2016 at 10:37, Yang Liu <liuya...@gmail.com> wrote:
> struct = """
> typedef struct {
> struct nlmsghdr nlh;
> struct inet_diag_req diag_req;
> }nlreq_t;
>
> /* Creates a new netlink request. */
> nlreq_t *nlreq_create();
> /* Destroys a netlink request */
> void nlreq_destroy(nlreq_t *req);
> """

If that's all you pass to ffi.cdef(), then indeed there is a problem:
the type nlreq_t is a structure whose fields are unknown structures.
This is what it complains about. I agree the error message could be
clearer, and occur earlier, when running build_nl.py. (I'll see about
that.)

The problem is that cffi doesn't know anything about "struct
nlmsghdr"; you can't have a field like that. In C you have the same
problem: the code above doesn't compile, unless you add the
``#include`` that really defines the types ``struct nlmsghdr`` and
``struct inet_diag_req``.


A bientôt,

Armin.

Yang Liu

unread,
Aug 15, 2016, 11:07:55 PM8/15/16
to python-cffi, ar...@tunes.org
Hi,Rigo

> The problem is that cffi doesn't know anything about "struct 
nlmsghdr";
I'm little confuse about that , cause I did add this headers in my script

```
header = """
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h> /* for sa_family_t */
#include <linux/inet_diag.h>
#include <linux/netlink.h>
"""
ffibuilder.set_source("_netlink", header + struct 
```


And I also checked that the types ``struct nlmsghdr``  is definded in ``linux/netlink.h``
also ``struct inet_diag_req`` in ``linux/inet_diag.h``

I use this same `include` defines in my C code,compile and works fine.




在 2016年7月31日星期日 UTC+8下午8:38:38,Armin Rigo写道:

Armin Rigo

unread,
Aug 17, 2016, 5:31:25 AM8/17/16
to pytho...@googlegroups.com
Hi,

On 16 August 2016 at 05:07, Yang Liu <liuya...@gmail.com> wrote:
>> The problem is that cffi doesn't know anything about "struct
> nlmsghdr";
> I'm little confuse about that , cause I did add this headers in my script

No, you need to write at least some definition of this struct in the cdef().
It's because CFFI needs to know what size it has and what fields
you're interested in and what type they have. It cannot guess all of
this by looking inside the headers---just like it cannot guess that
there is a function that you want to call and its signature; you need
to repeat that function declaration in cdef().

In other words, you pass to cdef() this:

"""
typedef struct {
struct nlmsghdr nlh;
struct inet_diag_req diag_req;
}nlreq_t;
"""

but it makes little sense to give this but not tell anything about the
two structs that are used inside (and I fixed CFFI to complain about
that).

You don't have to copy the whole definition of the structures; you can
declare them in the cdef() using "...;" in addition to any field
you're really interested in. At a minimum, you need:

"""
struct nlmsghdr {
...;
};
"""


A bientôt,

Armin.
Reply all
Reply to author
Forward
0 new messages