On Tue, Sep 22, 2009 at 02:56:05AM -0400, Mike Kaplinskiy wrote:
On Tue, Sep 22, 2009 at 1:09 AM, Vitaliy Margolen wine-devel@kievinfo.com wrote:
Ben Klein wrote:
The question remains, how exactly does FIELD_OFFSET work, and does it end up dereferencing ca[5]?
It does pointer arithmetic and does not dereference anything. "ca[5]" is the same as "(ca + 5)" or on lower level "((char*)ca + 5*sizeof(ca[0]))" and does not require any dereferencing.
It does, since field offset macro takes the easy approach: #define FIELD_OFFSET(type, field) ((LONG)(INT_PTR)&(((type *)0)->field))
which basically dereferences a null pointer to get the offset. This would be a bug in cppcheck since we don't actually dereference ca[5]. Moreover, since cppcheck doesn't catch the similar FIELD_OFFSET uses as bugs, it seems that it is mistaking ca[5] for the local ca, as opposed to the cs_t->ca.
I suspect that the above is technically illegal C. Mainly because pointer arithmetic is only defined for pointers to objects - and no object can have the address 0.
This is why offsetof() is defined as a builtin in more recent GCC.
The case in question tries to evaluate: ((LONG)(INT_PTR)&(((type *)0)->ca[5])) which does seem to contain a reference to beyond the end of the array!
Modern C allows the last entry of a struct to be ca[] (ie no array bound) for these situations where a structure will be malloced with dynamic size.
There is, however, a fubar in the standard. offsetof() is defined to return a compile-time constant - so the result can be used as an array size etc. However there are times when you want to do: offsetof(type, array_member[expression]) and this now reported as illegal by gcc unless 'espression' is a compile time constant :-(
David