(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]