Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Jun 2011 19:13:44 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        mdf@FreeBSD.org
Cc:        freebsd-hackers <freebsd-hackers@FreeBSD.org>, Bruce Evans <brde@optusnet.com.au>
Subject:   Re: sizeof(function pointer)
Message-ID:  <20110601183251.I1061@besplex.bde.org>
In-Reply-To: <BANLkTimctcBWRrYVLyc-WLgePyCXqaPTGA@mail.gmail.com>
References:  <BANLkTimctcBWRrYVLyc-WLgePyCXqaPTGA@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 31 May 2011 mdf@FreeBSD.org wrote:

> I am looking into potentially MFC'ing r212367 and related, that adds
> drains to sbufs.  The reason for MFC is that several pieces of new
> code in CURRENT are using the drain functionality and it would make
> MFCing those changes much easier.
>
> The problem is that r212367 added a pointer to a drain function in the
> sbuf (it replaced a pointer to void).  The C standard doesn't
> guarantee that a void * and a function pointer have the same size,
> though its true on amd64, i386 and I believe PPC.  What I'm wondering
> is, though not guaranteed by the standard, is it *practically* true
> that sizeof(void *) == sizeof(int(*)(void)), such that an MFC won't
> break binary compatibility for any supported architecture?  (The

Only on supported arches.

> standard does guarantee, though not in words, that all function
> pointers have the same size, since it guarantees that pointers to
> functions can be cast to other pointers to functions and back without
> changing the value).

No, it doesn't guarantee that they have the same size.  The casts may
change inything in the representation including the size.

In 1995 I added intfptr_t, uintfptr_t and fptrdiff_t to FreeBSD to
handle this problem in the profil(2) APIs.  You can check the MD
definitions of these to verify that their size is always the same as
the sizeof(void *).  There are some style bugs and namespace issues
with these.  The definitions in /sys/*/include/_types.h are clean, but
are mostly not used in their primary consumer /sys/*/include/profile.h.
intfptr_t and uintfptr_t are bogusly declared for the kernel in a bogus
declaration section in /sys/types.h.  They are intentionally kept out
of general headers, but even the kernel doesn't really need them there,
unless they are used for more than profiling and then you might need
them outside the kernel.

> Another possibility is to malloc a blob that is sizeof(int(*)(void))
> and store that in a renamed s_unused; this is a bit messier but
> guaranteed to work.  I'd just rather the code be an MCF instead of a
> partial re-write.

It is only guaranteed to work if the value is converted to the actual
function pointer type before use.  (At least for use as a function
pointer.)

Someone pointed out that POSIX now requires function pointers to have
the same representation as void *.  This is a bug in POSIX IMO.  It
isn't in the 2001 version.  I think POSIX had to do something for
broken parts of dlcfn APIs.  Hopefully this isn't required generally.
Requiring all function pointers to be convertible to void * and back
without breaking them is bad enough, but requiring the same representation
is much more restrictive.  It breaks any system that has type info in
the pointers.  The C standard is careful not to require this breakage
even for data pointers.

Someones pointed out that ia64 function pointers are actually handles.
Systems that want to put type info in pointers would have to use handles
instead of actual pointers to give the same representation, even if this
is not the natural ABI.  Whether handle values are useful when the data
that they point to is unavailable is unclear.  The profiling ABIs mainly
need the function pointers (converted to integers) as ids, and handle
values are hopefully enough for that.  If not, the conversion needs to
mangle the values sufficiently for uniqueness.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20110601183251.I1061>