cppcheck sept 18 redux

David Laight david at l8s.co.uk
Tue Sep 22 12:28:10 CDT 2009


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 at 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

-- 
David Laight: david at l8s.co.uk



More information about the wine-devel mailing list