(Sorry, this got stuck and didn't go out as I thought.)

> From: [EMAIL PROTECTED] On Behalf Of Victor Duchovni
> Sent: Wednesday, 16 January, 2008 19:30

> On Wed, Jan 16, 2008 at 05:33:13PM -0600,
> [EMAIL PROTECTED] wrote:
>
> > So this is from 0.9.8g's pem.h:
> >
> > #define   PEM_read_SSL_SESSION(fp,x,cb,u) (SSL_SESSION
> *)PEM_ASN1_read( \
> > (char *(*)())d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,fp,(char **)x,cb,u)

> > void *  PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE
> *fp, void **x,
> > pem_password_cb *cb, void *u);
> >
> > Anyone notice a problem here?
> >
> > That first argument to PEM_ASN1_read will never, ever be the right type.
> >
> > char * != void *
> >
>
> No actual problem, in ANSI C pointers can be freely converted between
> (type *) and (void *) and back.
>
Actual pointers can. Well, data pointers; Standard C (for 18 years now
ISO as well as ANSI) does not require this for function pointers, although
other standards like POSIX/XPG do, and commonly it also works.

But function-returning-T and function-returning-U are NOT required
to be compatible, and as a result calling the former through a pointer
having the latter type isn't guaranteed. I have worked on a system
where e.g. int* f1() and char* f2() are quite different, and using
( char*(*)() ) f1 will produce all kinds of crashes and corruption
(because int* and char* have different representations, and using
the bits that are actually an int* as if they were a char* is wrong).

For char* versus void* in particular, this is much less likely,
since they are required by Standard C to have the same representation;
according to a footnote this is 'intended' to allow substitution
in several places including here. Formally footnotes are nonnormative
and an implementor can break this by using a different calling convention
and be conforming, but I can't imagine why one would want to.

Standard C does allow you to cast any function pointer type to any
other funcptr type _and back to the/a correct type_, and _then_
using it to call is guaranteed to work. But not while it is 'wrong'.

Similarly, casting a pointer-to-pointer-type like (T**)& Uptr
and using it isn't guaranteed to work, and will in fact fail on the
platform I mentioned above for some combinations of T and U.
In particular it will fail for void* or char* versus any struct*,
and all the d2i's I've had occasion to look at are for struct types.
(This one is in the FAQL for comp.{lang,std}.c showing people have
in fact encountered it in the past, although in the few years I
have been reading them consistently it has not come up 'for real'.)

To absolutely-standard fix this we would have to make all the d2i
routines, and all the 'somedata' pointers, use the same actual type,
such as void*. Besides being a lot of work for no practical benefit,
this gives up too much otherwise useful and helpful type information.

A theoretical compromise might be to use an opaque struct type;
Standard C does require that all pointers _to structs_ have the
same representation (and similarly unions, not relevant here,
but NOT enums); as above the same representation doesn't actually
normatively require substitutability, but in practice it will work.
This is what C++ does; pointers (and references) to class types are
polymorphic within a (defined but unbounded) hierarchy, but not e.g. int* .
This is still a lot of work though, and not needed on mainstream
architectures where _all_ pointer types are implemented the same.



______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to