Re: Sadistic C compiler...
On Thu, Jan 20, 2000, Richard Levitte - VMS Whacker wrote: babinebell I think we should seperate the functions handling values babinebell and the functions handling callbacks: babinebell babinebell int BIO_ctrl_callback(BIO *bp,int cmd,long larg,int (*cb)()); Hmm, actually, I like that alternative. That allows us to go around the whole union/pass-by-value/and-so-on brouhaha... :-) Looks ok. Will you implement it? __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
On Wed, Jan 26, 2000, Bodo Moeller wrote: On Thu, Jan 20, 2000, Richard Levitte - VMS Whacker wrote: Hmm, actually, I like that alternative. That allows us to go around the whole union/pass-by-value/and-so-on brouhaha... :-) Looks ok. Will you implement it? Here "you" == Richard, in case it wasn't clear. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
bodo babinebell I think we should seperate the functions handling values bodo babinebell and the functions handling callbacks: bodo babinebell bodo babinebell int BIO_ctrl_callback(BIO *bp,int cmd,long larg,int (*cb)()); bodo bodo Hmm, actually, I like that alternative. That allows us to go around bodo the whole union/pass-by-value/and-so-on brouhaha... :-) bodo bodo Looks ok. Will you implement it? Sure. -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
It's *not* VMS specific! DEC C 6.2 for Unix issues very similar warning. But it looks like DEC has VMS specific reason to be nervous about the matter. Consider the following code: #pragma required_pointer_size save /* Save the previous pointer size */ #pragma required_pointer_size 64 /* Set pointer size to 64 bits */ typedef void *ptr_64; /* Define a 64-bit char pointer */ typedef void (*func_ptr64) (); #pragma required_pointer_size restore /* Restore the pointer size */ main () { printf ("%d%d%d%d\n",sizeof(void(*)()),sizeof(void *), sizeof(func_64),sizeof(ptr_64)); } It prints 4488! I.e. if program is compiled without /POINTER=64 command-line option:-) The worst is that it's possible to have say a function returning 64-bit pointer in one module declared as function returning 32-bit pointer in another module and link those modules together... Well, it might still work as arguments are passed and results returned through 64-bit register in either case, but the potential is there. What would definitely break is a pointer to 64-bit pointer vs. pointer to a 32-bit pointer, huh? Further references: http://www.digital.com/info/DTJM05/DTJM05HM.HTM http://www.digital.com/info/DTJM06/DTJM06HM.HTM Cheers. Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
babinebell I think we should seperate the functions handling values babinebell and the functions handling callbacks: babinebell babinebell int BIO_ctrl_callback(BIO *bp,int cmd,long larg,int (*cb)()); babinebell babinebell Is not nice, requires changing of some structures but babinebell seems to be the best save way... Hmm, actually, I like that alternative. That allows us to go around the whole union/pass-by-value/and-so-on brouhaha... :-) -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED] __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Richard Levitte - VMS Whacker [EMAIL PROTECTED]: Let me see if I got it all. So far, I've seen the following alternatives: 1. ignore the problem (obviously not the right thing to do :-)). 2. take the parameter in question as we do today, but use a union so the compiler will shut up (which is a fancy way of ignoring the problem). 3. whenever the passed parameter is a function pointer, use double indirection and assume the caller has really passed a reference to a function pointer. 4. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by value. 5. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by reference. Actually, 4 and 5 are basically the same. No, 5 is to 4 what (for function pointers) 3 is to 1. Choices 1 and 2 are really just as bad, they're designed to ignore the problem instead of dealing with it. Choice 3 assumes that the parameter ni question will be prototyped and used like this: int foo (..., void *parg, ...) { /* ... */ int (*fptr)() = *(int (**)())parg; /* ... */ } It's a good way to deal with the problem in what could be perceived as a safe way, but for a detail: there's no way to see from the API that function pointers need to be handled differently than other pointers when passed down to the functino using them ("doall" and "ctrl" functions...), and the compiler will not give a hint. It will give a hint! Just don't use casts, and the compiler will complain when you try to pass a function pointer directly. Simarly, the function using the function pointer can be written without casts if it is using the pointer correctly; if it's incorrect, you need casts to make the warning go away. And yes, there will be the problem of binary compatibility in all choices but 1 and 2... Choice 4 should be binary compatible as well, because on platforms where choice 1 and 2 work in practice both types of pointers have the same length, so probably the union won't be any different. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Richard Levitte - VMS Whacker wrote: 4. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by value. 5. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by reference. Actually, 4 and 5 are basically the same. There's a memory management issue with 5 that 4 cures. Cheers, Ben. -- SECURE HOSTING AT THE BUNKER! http://www.thebunker.net/hosting.htm http://www.apache-ssl.org/ben.html "My grandfather once told me that there are two kinds of people: those who work and those who take the credit. He told me to try to be in the first group; there was less competition there." - Indira Gandhi __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Andy Polyakov [EMAIL PROTECTED]: 5. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by reference. Choices 4 and 5 assumes that the parameter in question will be prototyped and used like this: int foo(..., union fn_n_data parg, ...) { /* ... */ int (*fptr)() = (int (*)())(parg.fn); /* ... */ } Why assign? parg.fn() (#4) and parg-fn() (#5) suffice and are perfectly readable/debuggable, aren't they? In the above example, yes; but not when it's really int (*fptr)(int, char) = (int (*)())(parg.fn); or even long (*fptr)(int, char) = (int (*)())(parg.fn); My vote is #5 for crypto/mem_dbg.c, crypto/bio/bss_conn.c, ssl/s3_lib.c with new calls and separate ctl codes for binary compatibility [...] I don't think it's worth to blow up the code that much to get binary compatibility (but by adding a couple of lines of these "switch" statements we can generate error messages that tell everyone to change their programs -- then, a version or two later, we can get rid of this extra code). It's easy to provide source code compatibility except when SSL_ctrl and the other similar functions are called directly -- to catch these cases we should slightly rename the SSL_ctrl command codes to cause compiler errors for programs that call it anyway. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro Why pass a reference? C has been able to passreturn aggregate types since appro v7 :) appro Because *that* would *definitely* have impact on *a lot* of things. Pass appro by value is an option only if you reimplement all function dealing with appro whitened parameter to callback functions. I mean if you want to stick to appro void *, then pass by reference is the only (ANSI compliant) option. Let me see if I got it all. So far, I've seen the following alternatives: 1. ignore the problem (obviously not the right thing to do :-)). 2. take the parameter in question as we do today, but use a union so the compiler will shut up (which is a fancy way of ignoring the problem). 3. whenever the passed parameter is a function pointer, use double indirection and assume the caller has really passed a reference to a function pointer. 4. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by value. 5. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by reference. Absolutely yes. Actually, 4 and 5 are basically the same. Well, it's actually 3 and 5 which are the same. I.e. in the sense that equivalent machine code is generated in both cases. In case #3 you do *((**))p() and in case #5 - (union *)p-func(). The advantage of the #5 over the #3 is that it's more error prone (as *you* have pointed out yourself:-). Choices 1 and 2 are really just as bad, they're designed to ignore the problem instead of dealing with it. Yes. Choice 3 assumes that the parameter ni question will be prototyped and used like this: int foo (..., void *parg, ...) { /* ... */ int (*fptr)() = *(int (**)())parg; /* ... */ } It's a good way to deal with the problem in what could be perceived as a safe way, but for a detail: there's no way to see from the API that function pointers need to be handled differently than other pointers when passed down to the functino using them ("doall" and "ctrl" functions...), and the compiler will not give a hint. Well, you probably don't have to tell the difference at the *published* "API" level (API is in quotes as there's a lot of macros). We have crypto/mem_dbg.c, crypto/bio/bss_conn.c, ssl/s3_lib.c and crypto/objects/o_names.c offending the compiler. First is no problem at all (i.e. either #3 or #5) and it even remains binary compatible. Second and third can be fixed by promoting some macros to calls (which is a "good thing(tm)") and ensure *source* code compatibility and can be done with minimal changes (again provided that #3 or #4 are chosen). It's even possible to provide binary compatibility in first three by introducing separate ctl codes dealing with unions pass by value and pass by reference. Pass by value can be guarded with "if(sizeof(void(*)())!=sizeof(void*))abort();" ensuring intended behavior. I keep my mouth shut about o_names.c for this time as I haven't got the whole picture after 5 mins staring at it (but I'll get there eventually:-). Choices 4 and 5 assumes that the parameter in question will be prototyped and used like this: int foo(..., union fn_n_data parg, ...) { /* ... */ int (*fptr)() = (int (*)())(parg.fn); /* ... */ } Why assign? parg.fn() (#4) and parg-fn() (#5) suffice and are perfectly readable/debuggable, aren't they? I dunno about you, but I really don't like choice 3. At all. My gut feeling is that it's way error prone, and may be quite hard to debug. As I see it, the only real way to make it type safe, ANSI compliant and avoid error proneness is to stick with choices 4 or 5. My vote is #5 for crypto/mem_dbg.c, crypto/bio/bss_conn.c, ssl/s3_lib.c with new calls and separate ctl codes for binary compatibility (I can fix up bss_conn.c and s3_lib.c to *show* what I mean). I'll be back about o_names.c... And yes, there will be the problem of binary compatibility in all choices but 1 and 2... *and* #4 on the supported platforms. I mean on all *currently* supported platforms sizeof(void(*)()) == sizeof(void *) and pass of union (by value) is *equivalent* to pass of pointer (by value). Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro My vote is #5 for crypto/mem_dbg.c, crypto/bio/bss_conn.c, appro ssl/s3_lib.c with new calls and separate ctl codes for binary appro compatibility (I can fix up bss_conn.c and s3_lib.c to *show* appro what I mean). I'll be back about o_names.c... Below is what I ment for bss_conn.c. It's both source and binary compatible and those are the *only* changes required. If everybody agrees on it, I'll fix-up s3_lib.c in same way directly in cvs tree (throwing some extra comments around and "promoting" even *_get_info_callback to call for consistency:-) Cheers. Andy. *** ./bio.h.origMon Sep 27 16:00:09 1999 --- ./bio.h Thu Jan 20 16:57:00 2000 *** *** 116,121 --- 116,122 /* callback is int cb(BIO *bio,state,ret); */ #define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */ #define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ + #define BIO_CTRL_ANSI_SET_CALLBACK16 /* opt - set callback function */ #define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ *** *** 456,462 --- 457,467 size_t BIO_ctrl_wpending(BIO *b); #define BIO_flush(b) (int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL) #define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0,(char *)cbp) + #if 0 #define BIO_set_info_callback(b,cb) (int)BIO_ctrl(b,BIO_CTRL_SET_CALLBACK,0,(char *)cb) + #else + int BIO_set_info_callback (BIO *b, int (*cb)()); + #endif /* For the BIO_f_buffer() type */ #define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL) *** ./bss_conn.c.orig Thu Jun 10 19:00:10 1999 --- ./bss_conn.cThu Jan 20 16:54:36 2000 *** *** 447,452 --- 447,454 return(ret); } + typedef union { int (*func) (); void *ptr; } sin_of_ansification; + static long conn_ctrl(BIO *b, int cmd, long num, char *ptr) { BIO *dbio; *** *** 573,579 (void)BIO_set_info_callback(dbio,data-info_callback); break; case BIO_CTRL_SET_CALLBACK: ! data-info_callback=(int (*)())ptr; break; case BIO_CTRL_GET_CALLBACK: { --- 575,587 (void)BIO_set_info_callback(dbio,data-info_callback); break; case BIO_CTRL_SET_CALLBACK: ! if (sizeof(void (*)()) == sizeof(void *)) ! { ! sin_of_ansification sin; ! sin.ptr = ptr; ! data-info_callback=sin.func; ! } ! elseabort (); break; case BIO_CTRL_GET_CALLBACK: { *** *** 583,588 --- 591,599 *fptr=data-info_callback; } break; + case BIO_CTRL_ANSI_SET_CALLBACK: + data-info_callback=((sin_of_ansification *)ptr)-func; + break; default: ret=0; break; *** *** 614,618 --- 625,636 } } + int BIO_set_info_callback (BIO *b, int (*cb)()) + { + sin_of_ansification not_a_sin; + + not_a_sin.func = cb; + return BIO_ctrl (b,BIO_CTRL_ANSI_SET_CALLBACK,0,(void *)not_a_sin); + } #endif __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro Well, it's actually 3 and 5 which are the same. I.e. in the Ah, right, I made the comparison from a language semantics point of view... appro It's a good way to deal with the problem in what could be perceived as appro a safe way, but for a detail: there's no way to see from the API that appro function pointers need to be handled differently than other pointers appro when passed down to the functino using them ("doall" and "ctrl" appro functions...), and the compiler will not give a hint. appro Well, you probably don't have to tell the difference at the appro *published* "API" level (API is in quotes as there's a lot of appro macros). Uhmm... Why not? appro Why assign? parg.fn() (#4) and parg-fn() (#5) suffice and are perfectly appro readable/debuggable, aren't they? Yes. Consider the above an example, nothing else. The real thing would probably be to assign a callback variable... appro I dunno about you, but I really don't like choice 3. At all. My gut appro feeling is that it's way error prone, and may be quite hard to debug. appro As I see it, the only real way to make it type safe, ANSI compliant appro and avoid error proneness is to stick with choices 4 or 5. appro My vote is #5 for crypto/mem_dbg.c, crypto/bio/bss_conn.c, appro ssl/s3_lib.c with new calls and separate ctl codes for binary appro compatibility (I can fix up bss_conn.c and s3_lib.c to *show* appro what I mean). I'll be back about o_names.c... Why have it different for o_names.c? appro And yes, there will be the problem of binary compatibility in all appro choices but 1 and 2... appro *and* #4 on the supported platforms. I mean on all *currently* appro supported platforms sizeof(void(*)()) == sizeof(void *) and appro pass of union (by value) is *equivalent* to pass of pointer (by appro value). Quite right. Sounds like the ultimate way of choice would be #4... -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro *** ./bio.h.origMon Sep 27 16:00:09 1999 appro --- ./bio.h Thu Jan 20 16:57:00 2000 appro *** appro *** 116,121 appro --- 116,122 appro /* callback is int cb(BIO *bio,state,ret); */ appro #define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */ appro #define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ appro + #define BIO_CTRL_ANSI_SET_CALLBACK16 /* opt - set callback function */ appro appro #define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ appro appro *** appro *** 456,462 appro --- 457,467 appro size_t BIO_ctrl_wpending(BIO *b); appro #define BIO_flush(b) (int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL) appro #define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0,(char *)cbp) appro + #if 0 appro #define BIO_set_info_callback(b,cb) (int)BIO_ctrl(b,BIO_CTRL_SET_CALLBACK,0,(char *)cb) appro + #else appro + int BIO_set_info_callback (BIO *b, int (*cb)()); appro + #endif appro appro /* For the BIO_f_buffer() type */ appro #define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL) appro *** ./bss_conn.c.orig Thu Jun 10 19:00:10 1999 appro --- ./bss_conn.cThu Jan 20 16:54:36 2000 appro *** appro *** 447,452 appro --- 447,454 appro return(ret); appro } appro appro + typedef union { int (*func) (); void *ptr; } sin_of_ansification; appro + appro static long conn_ctrl(BIO *b, int cmd, long num, char *ptr) appro { appro BIO *dbio; appro *** appro *** 573,579 appro (void)BIO_set_info_callback(dbio,data-info_callback); appro break; appro case BIO_CTRL_SET_CALLBACK: appro ! data-info_callback=(int (*)())ptr; appro break; appro case BIO_CTRL_GET_CALLBACK: appro { appro --- 575,587 appro (void)BIO_set_info_callback(dbio,data-info_callback); appro break; appro case BIO_CTRL_SET_CALLBACK: appro ! if (sizeof(void (*)()) == sizeof(void *)) appro ! { appro ! sin_of_ansification sin; appro ! sin.ptr = ptr; appro ! data-info_callback=sin.func; appro ! } appro ! elseabort (); appro break; appro case BIO_CTRL_GET_CALLBACK: appro { appro *** appro *** 583,588 appro --- 591,599 appro *fptr=data-info_callback; appro } appro break; appro + case BIO_CTRL_ANSI_SET_CALLBACK: appro + data-info_callback=((sin_of_ansification *)ptr)-func; appro + break; appro default: appro ret=0; appro break; appro *** appro *** 614,618 appro --- 625,636 appro } appro } appro appro + int BIO_set_info_callback (BIO *b, int (*cb)()) appro + { appro + sin_of_ansification not_a_sin; appro + appro + not_a_sin.func = cb; appro + return BIO_ctrl (b,BIO_CTRL_ANSI_SET_CALLBACK,0,(void *)not_a_sin); appro + } appro #endif Hmm. That's basically an anonymous choice 4 and 5 (depending on ctl code). My thought about that one was that BIO_ctrl would be declared and defined to take a 'sin_of_ansification *' as argument instead of a 'void *' (a non-anonymous variant 4). This would still be binary compatible (as you noted), but would force new users to use a more type-safe approach to the control functions. Also, in that case, new ctl codes would not be required. -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Hmm. That's basically an anonymous choice 4 and 5 (depending on ctl code). Yes, that was my vote/proposal. Anonymous/whitened pointer argument is the key to binary compatibility (at _ctrl level) and having anything (anything at all) passed by value is not the right thing to do. My thought about that one was that BIO_ctrl would be declared and defined to take a 'sin_of_ansification *' ^ you vote for #4, no star here. as argument instead of a 'void *' (a non-anonymous variant 4). But it breaks *source* code compatibility and old users gonna get (really) frustrated. This would still be binary compatible (as you noted), but would force new users to use a more type-safe approach to the control functions. Also, in that case, new ctl codes would not be required. Is a new code a problem? Andy. P.S. In reply to previous message. Why have it different for o_names.c? It's uses private interface routines and #4 might be the appropriate option. Well, "private" means "not likely used by an average OpenSSL developer." __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro My thought about that one was that BIO_ctrl would be declared appro and defined to take a 'sin_of_ansification *' appro ^ you vote for #4, no star here. Oops :-). appro as argument instead of a appro 'void *' (a non-anonymous variant 4). appro But it breaks *source* code compatibility and old users gonna appro get (really) frustrated. That is true, but on the other hand, there have been many discussions that seem to point to a need to break source compatibility. That or doing a triple bendover at some point... And as far as I understand, source compatibility has already been broken. Here's another Decision for us: clean up and break source compatibility on some points or work really hard at maintaining source compatibility and building something that has potential of being quite messy. appro This would still be binary appro compatible (as you noted), but would force new users to use a more appro type-safe approach to the control functions. Also, in that case, new appro ctl codes would not be required. appro Is a new code a problem? Yes, in a way: it adds to the confusion. Imagine having to answer the question "There are two ways to do exactly the same thing. Why? Which one is the prefered way?" with something other than "hysterical raisins" (eh, "historical reasons"...). There *is* the question of maintainability, and I sometimes really wonder where we're heading with that in mind. appro P.S. In reply to previous message. appro Why have it different for o_names.c? appro It's uses private interface routines and #4 might be the appropriate appro option. Well, "private" means "not likely used by an average OpenSSL appro developer." I've never trusted that kind of assumption. Especially with the current state of documentation :-). -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
And what if sizeof (void (*)()) != sizeof (void *)? Think MS-DOS and all those sick small/medium/large/huge memory models if you have to. I realize it's a sick thought, but that's what the compiler complains about and that's why "such a cast is not permitted by the standard." In this particular case Do you mean DEC C, VMS or something? I think the compiler is worried about alignment issues. Functions need to be aligned in a very specific way. So as doubles, longs, integers, shorts (on most platforms). Alignment requirement for functions aren't extraordinary. I don't have standard either, but http://www.c9x.org/ used to have draft on-line which is close enough for any practical purpose. Unfortununately their site looks messed up right now, but I have a PDF copy at http://fy.chalmers.se/~appro/c9x-draft.pdf till they get things straighten out. Relevant quotes: "7. A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object. 8. A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined." That's it. Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro Why not simply relax the compiler with /STANDARD=RELAXED or whatever:-) Sure, we can do that. Is that the right thing to do? ":-)" was actually ment to designate the wrong thing. We need to decide if this is something that actually warrants our attention, or if we think it can be safely ignored. My vote is "it should be fixed, eventually." Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro Why pass a reference? C has been able to passreturn aggregate types since appro v7 :) appro Because *that* would *definitely* have impact on *a lot* of things. Pass appro by value is an option only if you reimplement all function dealing with appro whitened parameter to callback functions. I mean if you want to stick to appro void *, then pass by reference is the only (ANSI compliant) option. Let me see if I got it all. So far, I've seen the following alternatives: 1. ignore the problem (obviously not the right thing to do :-)). 2. take the parameter in question as we do today, but use a union so the compiler will shut up (which is a fancy way of ignoring the problem). 3. whenever the passed parameter is a function pointer, use double indirection and assume the caller has really passed a reference to a function pointer. 4. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by value. 5. Have the caller tuck the parameter in a union that will represent function pointers as well as other pointers, and pass that union by reference. Actually, 4 and 5 are basically the same. Choices 1 and 2 are really just as bad, they're designed to ignore the problem instead of dealing with it. Choice 3 assumes that the parameter ni question will be prototyped and used like this: int foo (..., void *parg, ...) { /* ... */ int (*fptr)() = *(int (**)())parg; /* ... */ } It's a good way to deal with the problem in what could be perceived as a safe way, but for a detail: there's no way to see from the API that function pointers need to be handled differently than other pointers when passed down to the functino using them ("doall" and "ctrl" functions...), and the compiler will not give a hint. Choices 4 and 5 assumes that the parameter in question will be prototyped and used like this: int foo(..., union fn_n_data parg, ...) { /* ... */ int (*fptr)() = (int (*)())(parg.fn); /* ... */ } (yeah, I know, choice adds a level of indirection) It's a good way to make it plainly visible to the user of that function that he/she will have to do something special with that parameter to get it accepted. Have I understood it all right? I dunno about you, but I really don't like choice 3. At all. My gut feeling is that it's way error prone, and may be quite hard to debug. As I see it, the only real way to make it type safe, ANSI compliant and avoid error proneness is to stick with choices 4 or 5. Of course, that demands a little bit more work, and there's the risk of breaking a number of programs out there, but as someone (Stephen?) said, there are already a number of changes since 0.9.4 that may already break a number of programs. And yes, there will be the problem of binary compatibility in all choices but 1 and 2... -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro The function pointer *must* be inside a data object to make appro such constructs legal, appro But that's what Richard (subconsciously?) attempted to do in appro first place: Don't look at me, that part of the code was there in mem.c since eons... Sorry:-) I should have written "whomever who wrote this." void (*mem_callback)()=(void (*)())cb; ...^ %CC-I-NONSTANDCAST, In the initializer for mem_callback, "cb" of type "pointer to char", is being converted to "pointer to function () returning void". Such a cast is not permitted by the standard. As you can see, whatever you do with the current scheme, there will always be a conversion between function pointers and non-function pointers. appro so this is not silly at all. An alternative would be to use appro unions of a function pointer appro Why structures/unions? "lh_doall_arg(mh,(void (*)())cb_leak,(void appro *)mem_cb)" should do... Look at it more carefully. I don't cast pointer to function, but a pointer to pointer to function, which is perfectly portable/legal/legitimate/valid/compliant-with-standard/whatever. The easiest way to avoid the conversions noted above is to have a union like this: union foo { void *simple; int (*fn)(); }; and use it internally. You put whatever char * you want to convert to a functino pointer into simple and pull out the function pointer from fn, and vice versa. Just to make it clear. Are you going to pass the union by reference of by value? You have to pass by reference which is equivalent to what I proposed, but without unions. Passing by value would be wrong and compiler should complain. appro And I fail to understand why mem_cb has to be declared static? Not to be seen outside of the file? The sentence was rather I don't understand why it has to be declared *outside* CRYPTO_mem_leaks_cb scope. And that's what stands in the next one: appro It can be perfectly declared in CRYPTO_mem_leaks_cb scope which appro also makes it multi-thead safe, doesn't it? appro typedef void (*cb_t) (); appro appro static void cb_leak(MEM *m, void *cb) appro { appro void (*mem_callback)()=*((cb_t *)cb); You convert from void * to void (*)() (i.e. between a "simple type" and a function pointer). Nope, it's cast from a void pointer to pointer to pointer to function and fetch. DEC C will complain. Shall we bet:-) Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
bmoeller cb, bmoeller on the other hand, is the pointer to some data object; the bmoeller function that gets this pointer as an argument has to bmoeller retrieve the actual function pointer from inside this data bmoeller object, i.e. use *((void (**)()) arg) where arg is the void bmoeller * argument passed to it. Exactly my point. I chose to "typdef void (*cb_t)()" and then "*((cb_t *)arg)" as it's more readable. I was pondering such a solution, but I foresaw a problem with it: strcmp is the same as strcmp, Yes, but cb and cb aren't the same at all and we all know that. and that might be a difficult bug to find... Well, just make sure the union is passed by reference and do drop some comment around it. Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
bmoeller bit data pointers). To force C to convert values between bmoeller these types, you'd have to cast to some integer type inbetween: bmoeller bmoeller (void (*)()) (long) cb This may very well be a problem on architectures where a pointer is 64 bits while a long is 32 bits. I think that some versions of Compaq C on Alpha (VMS and True64) have this quirk... bmoeller But of course this is so complicated because it should never bmoeller be done and is not guaranteed to do anything useful. cb, bmoeller on the other hand, is the pointer to some data object; the bmoeller function that gets this pointer as an argument has to bmoeller retrieve the actual function pointer from inside this data bmoeller object, i.e. use *((void (**)()) arg) where arg is the void bmoeller * argument passed to it. I was pondering such a solution, but I foresaw a problem with it: strcmp is the same as strcmp, and that might be a difficult bug to find... -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Richard Levitte - VMS Whacker wrote: The easiest way to avoid the conversions noted above is to have a union like this: union foo { void *simple; int (*fn)(); }; and use it internally. You put whatever char * you want to convert to a functino pointer into simple and pull out the function pointer from fn, and vice versa. That assumes that the conversion the compiler is attempting to prevent can actually be done, which is not, of course, a valid assumption. The only way to do this validly is to make the functions actually take a foo * as their argument, surely? And yes, then you may end up with a memory management problem (though often not, coz I'll bet in most cases you can make the foo static). Cheers, Ben. -- SECURE HOSTING AT THE BUNKER! http://www.thebunker.net/hosting.htm http://www.apache-ssl.org/ben.html "My grandfather once told me that there are two kinds of people: those who work and those who take the credit. He told me to try to be in the first group; there was less competition there." - Indira Gandhi __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro Just to make it clear. Are you going to pass the union by appro reference of by value? You have to pass by reference which is appro equivalent to what I proposed, but without unions. Passing by appro value would be wrong and compiler should complain. As you have probably seen by now, I don't pass around any unions at all, I just use them as instruments to convert pointers. You see, I absolutely wanted to keep binary compatibility for now, or we would see a lot of things break silently all over the place, since most of these things happen in places where regular char pointers are passed as parameters as well (the diverse _ctrl() functions, for example). But it's very possible that we can make things more elegant, and also more complicated. We most apparently have pointers "of variable type", which basically is a union. For those parameters, we could simply enforce the use of a union, and provide a few macros to make it easier to handle. (oh, and yes, before you ask, in my min that union would be passed around by reference :-), but then we have the problem of handling temporary instances nicely) appro DEC C will complain. appro Shall we bet:-) Nope, you were right about that one. -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Ben Laurie wrote: Richard Levitte - VMS Whacker wrote: The easiest way to avoid the conversions noted above is to have a union like this: union foo { void *simple; int (*fn)(); }; and use it internally. You put whatever char * you want to convert to a functino pointer into simple and pull out the function pointer from fn, and vice versa. That assumes that the conversion the compiler is attempting to prevent can actually be done, which is not, of course, a valid assumption. The only way to do this validly is to make the functions actually take a foo * as their argument, surely? And yes, then you may end up with a memory management problem (though often not, coz I'll bet in most cases you can make the foo static). Hmmm. Do we have to use this on every platform, including those that handled it before? Can't we just have a macro or function that does the conversion? I.e. on most platforms it would be a macro which expands to a cast but on VMS it would end up calling a function. Steve. -- Dr Stephen N. Henson. http://www.drh-consultancy.demon.co.uk/ Personal Email: [EMAIL PROTECTED] Senior crypto engineer, Celo Communications: http://www.celocom.com/ Core developer of the OpenSSL project: http://www.openssl.org/ Business Email: [EMAIL PROTECTED] PGP key: via homepage. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro Just to make it clear. Are you going to pass the union by appro reference of by value? You have to pass by reference which is appro equivalent to what I proposed, but without unions. Passing by appro value would be wrong and compiler should complain. As you have probably seen by now, I don't pass around any unions at all, I just use them as instruments to convert pointers. And what if sizeof (void (*)()) != sizeof (void *)? Think MS-DOS and all those sick small/medium/large/huge memory models if you have to. I realize it's a sick thought, but that's what the compiler complains about and that's why "such a cast is not permitted by the standard." You see, I absolutely wanted to keep binary compatibility for now, or we would see a lot of things break silently all over the place, Why not simply relax the compiler with /STANDARD=RELAXED or whatever:-) Cheers. Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
And what if sizeof (void (*)()) != sizeof (void *)? Think MS-DOS and all those sick small/medium/large/huge memory models if you have to. I realize it's a sick thought, but that's what the compiler complains about and that's why "such a cast is not permitted by the standard." In this particular case I think the compiler is worried about alignment issues. Functions need to be aligned in a very specific way. Jeffrey Altman * Sr.Software Designer * Kermit-95 for Win32 and OS/2 The Kermit Project * Columbia University 612 West 115th St #716 * New York, NY * 10025 http://www.kermit-project.org/k95.html * [EMAIL PROTECTED] __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
The easiest way to avoid the conversions noted above is to have a union like this: union foo { void *simple; int (*fn)(); }; and use it internally. You put whatever char * you want to convert to a functino pointer into simple and pull out the function pointer from fn, and vice versa. That assumes that the conversion the compiler is attempting to prevent can actually be done, which is not, of course, a valid assumption. The only way to do this validly is to make the functions actually take a foo * as their argument, surely? And yes, then you may end up with a memory management problem (though often not, coz I'll bet in most cases you can make the foo static). Hmmm. Do we have to use this on every platform, including those that handled it before? Can't we just have a macro or function that does the conversion? I.e. on most platforms it would be a macro which expands to a cast but on VMS it would end up calling a function. It's *not* VMS specific! DEC C 6.2 for Unix issues very similar warning. Yes, it's just a warning, it's not a fatal error and generated code does the intended thing. It should also be pointed out that it (Unix version) does it only if invoked with -std1 flag which stands for maximum standard compliance! Do we have to use on every platform? Only if we want to claim that the toolkit is 100% ANSI C:-) For your information here're other offending casts: cc: Info: bss_conn.c, line 573: In this statement, "data-info_callback" of type "pointer to function () returning int", is being converted to "pointer to char" . Such a cast is not permitted by the standard. (nonstandcast) (void)BIO_set_info_callback(dbio,data-info_callback); --^ cc: Info: bss_conn.c, line 576: In this statement, "ptr" of type "pointer to cha r", is being converted to "pointer to function () returning int". Such a cast i s not permitted by the standard. (nonstandcast) data-info_callback=(int (*)())ptr; ---^ cc: Info: o_names.c, line 53: In this statement, "strcmp" of type "pointer to fu nction (pointer to const char, pointer to const char) returning int", is being c onverted to "pointer to char". Such a cast is not permitted by the standard. (n onstandcast) sk_push(names_hash,(char *)strcmp); ---^ cc: Info: o_names.c, line 54: In this statement, "lh_strhash" of type "pointer t o function (pointer to const char) returning unsigned long", is being converted to "pointer to char". Such a cast is not permitted by the standard. (nonstandca st) sk_push(names_cmp,(char *)lh_strhash); --^ cc: Info: o_names.c, line 59: In this statement, "hash_func" of type "pointer to function () returning unsigned long", is being converted to "pointer to char". Such a cast is not permitted by the standard. (nonstandcast) sk_set(names_hash,ret,(char *)hash_func); --^ cc: Info: o_names.c, line 61: In this statement, "cmp_func" of type "pointer to function () returning int", is being converted to "pointer to char". Such a cas t is not permitted by the standard. (nonstandcast) sk_set(names_cmp,ret,(char *)cmp_func); -^ cc: Info: o_names.c, line 63: In this statement, "free_func" of type "pointer to function () returning void", is being converted to "pointer to char". Such a c ast is not permitted by the standard. (nonstandcast) sk_set(names_free,ret,(char *)free_func); --^ cc: Info: o_names.c, line 77: In this statement, "sk_value(...)" of type "pointe r to char", is being converted to "pointer to function () returning int". Such a cast is not permitted by the standard. (nonstandcast) cmp=(int (*)())sk_value(names_cmp,a-type); ---^ cc: Info: o_names.c, line 93: In this statement, "sk_value(...)" of type "pointe r to char", is being converted to "pointer to function () returning unsigned lon g". Such a cast is not permitted by the standard. (nonstandcast) hash=(unsigned long (*)())sk_value(names_hash,a-type); --^ cc: Info: o_names.c, line 163: In this statement, "sk_value(...)" of type "point er to char", is being converted to "pointer to function () returning void". Suc h a cast is not permitted by the standard. (nonstandcast) f=(void (*)())sk_value(names_free,ret-type); --^ cc: Info: o_names.c, line 195: In this statement, "sk_value(...)" of type "point er to char", is being converted to "pointer to function () returning void". Suc h a cast is not permitted by the standard.
RE: Sadistic C compiler...
Why pass a reference? C has been able to passreturn aggregate types since v7 :) only way to do this validly is to make the functions actually take a foo* as their argument, surely? Yes you must do that. I'll bet in most cases you can make the foo static Unless I misunderstand what you mean, that's not thread-safe. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Jeffrey Altman wrote: . 4 fn(x, y, z);/* Function call: functions */ /* x and y, and array z */ /* passed as addresses */ A function pointer may not be an "address" -- in particular, on segmented architectures, a function pointer may not resolve to any regular storage class for the compiler/platform combo. Another reason not to try to cast function pointers ... -- QUI ME AMET, CANEM MEUM ETIAM AMET __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro Why not simply relax the compiler with /STANDARD=RELAXED or whatever:-) Sure, we can do that. Is that the right thing to do? I remember that at some point, it was "all hail ANSI C", something I support. But not only that, if this problem is enough to actually create errors on "MS-DOS and all those sick small/medium/large/huge memory models" or on other segmented architectures (I don't know that many, but...), is it then the right thing to tell the compiler to shut up so we don't have to bother with it. We need to decide if this is something that actually warrants our attention, or if we think it can be safely ignored. (I personally don't mind relaxing DEC C a bit, although it will sometimes take away half the fun :-). I know it will work correctly on VMS... and on the Unixen I play with) -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
On Tue, Jan 18, 2000 at 10:59:53AM +0100, Richard Levitte - VMS Whacker wrote: bit data pointers). To force C to convert values between these types, you'd have to cast to some integer type inbetween: (void (*)()) (long) cb This may very well be a problem on architectures where a pointer is 64 bits while a long is 32 bits. Exactly, which is why compilers should complain when someone attempts to do such things (with just one cast, as in OpenSSL -- two casts as above tell the compiler that the user pretends to know what he is doing). But of course this is so complicated because it should never be done and is not guaranteed to do anything useful. cb, on the other hand, is the pointer to some data object; the function that gets this pointer as an argument has to retrieve the actual function pointer from inside this data object, i.e. use *((void (**)()) arg) where arg is the void * argument passed to it. I was pondering such a solution, but I foresaw a problem with it: strcmp is the same as strcmp, and that might be a difficult bug to find... I see, this could become a problem (when using over-tolerant compilers that don't print warnings for such conversions). __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
RE: Sadistic C compiler...
Looks like a compiler bug; NULL is supposed to be safely castable to any pointer type, and compared against any pointer type. NULL is often a pound define and not a compiler name. Its definition is very frequently (char *)0 which is not comparable. Jeffrey Altman * Sr.Software Designer * Kermit-95 for Win32 and OS/2 The Kermit Project * Columbia University 612 West 115th St #716 * New York, NY * 10025 http://www.kermit-project.org/k95.html * [EMAIL PROTECTED] __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
RE: Sadistic C compiler...
SalzR Looks like a compiler bug; NULL is supposed to be safely SalzR castable to any pointer type, and compared against any pointer SalzR type. Depends on. If NULL is defined like this: #define NULL 0 then you're perfectly right, but if it's defined like this: #define NULL ((void *)0) then I'm dubious at least. I don't have the standard here, but I'm pretty sure it says that 0 can be cast to any pointer, not necessarely NULL. Compaq C did of course not complain when I replaced NULL with 0. Have you noticed, if you read The C++ Programming Language, how he completely avoids NULL and consequently uses 0 instead? I think he's got at least one clue on this issue. -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
"Salz, Rich" wrote: Why pass a reference? C has been able to passreturn aggregate types since v7 :) Good point. only way to do this validly is to make the functions actually take a foo* as their argument, surely? Yes you must do that. I'll bet in most cases you can make the foo static Unless I misunderstand what you mean, that's not thread-safe. It is if the function is always the same (which is what I meant). Cheers, Ben. -- SECURE HOSTING AT THE BUNKER! http://www.thebunker.net/hosting.htm http://www.apache-ssl.org/ben.html "My grandfather once told me that there are two kinds of people: those who work and those who take the credit. He told me to try to be in the first group; there was less competition there." - Indira Gandhi __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
RE: Sadistic C compiler...
In the ANSI standard C sense, there is no real difference between the C language and the supporting libraries. I don't have a copy of the standard handy, but I'm fairly sure it can be safely castable as I said before. Therefore if Compaq's C compiler #define's it as void*, then their "compiler" seems to have a bug. /r$ __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Richard Levitte - VMS Whacker [EMAIL PROTECTED]: [...] The easiest way to avoid the conversions noted above is to have a union like this: union foo { void *simple; int (*fn)(); }; and use it internally. You put whatever char * you want to convert to a functino pointer into simple and pull out the function pointer from fn, and vice versa. You cannot convert things this way, that would be just as broken as using casts. What you can do, of course, is put pointers into the appropriate union member ('simple' for data pointers, 'fn' for function pointers), pass the union to some function, and, in this function, take the same union member from the union passed as an argument. I thought you had done exactly that, but a second look in the commitlog shows that you have not (and it would make SSL_[CTX_]ctrl much more complicated, we'd have to change the prototype). The clean way (and not just another "clever hack") would be void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl, int is_export, int keylength)) { RSA *(**cb_ptr)(SSL *, int, int) = cb; /* cb_ptr is a data pointer, * not a function pointer */ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,0,cb_ptr); /* no cast necessary as * SSL_CTX_ctrl should * have "void *" in the * final argument */ } and in ssl3_ctrl (which is what SSL_CTX_ctrl ends up calling): long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) { [...] switch (cmd) { [...] case SSL_CTRL_SET_TMP_RSA_CB: { RSA *(**cb_ptr)(SSL *, int, int) = parg; s-cert-rsa_tmp_cb = *cb_ptr; } break; [...] } [...] } Instead of directly passing function pointers in disguise, a pass pointers to data objects containing the actual function pointers. Note that I'm using temporary variables instead of single-line commands involving casts because this way it can be hoped more compilers will print warnings or error messages in case of a typo -- the explicit cast from a function pointer value to void * was enough to bring gcc to silence, but without casts the compiler can see that you don't really intend to do such evil things. (SSL_CTX_ctrl, ssl3_ctrl et al. still have a char * argument where they should have a void * -- it's certainly trivial to change that.) __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
RE: Sadistic C compiler...
SalzR In the ANSI standard C sense, there is no real difference SalzR between the C language and the supporting libraries. It's useless to discuss it unless someone can cite the exact words of the standard here. Until then, we're just talking out of our behinds. -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Richard Levitte - VMS Whacker wrote: SalzR In the ANSI standard C sense, there is no real difference SalzR between the C language and the supporting libraries. It's useless to discuss it unless someone can cite the exact words of the standard here. Until then, we're just talking out of our behinds. That's never stopped us before :-) Steve. -- Dr Stephen N. Henson. http://www.drh-consultancy.demon.co.uk/ Personal Email: [EMAIL PROTECTED] Senior crypto engineer, Celo Communications: http://www.celocom.com/ Core developer of the OpenSSL project: http://www.openssl.org/ Business Email: [EMAIL PROTECTED] PGP key: via homepage. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Bodo Moeller wrote: The clean way (and not just another "clever hack") would be void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,RSA *(*cb)(SSL *ssl, int is_export, int keylength)) { RSA *(**cb_ptr)(SSL *, int, int) = cb; /* cb_ptr is a data pointer, * not a function pointer */ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA_CB,0,cb_ptr); /* no cast necessary as * SSL_CTX_ctrl should * have "void *" in the * final argument */ } and in ssl3_ctrl (which is what SSL_CTX_ctrl ends up calling): long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) { [...] switch (cmd) { [...] case SSL_CTRL_SET_TMP_RSA_CB: { RSA *(**cb_ptr)(SSL *, int, int) = parg; s-cert-rsa_tmp_cb = *cb_ptr; } break; [...] } [...] } Instead of directly passing function pointers in disguise, a pass pointers to data objects containing the actual function pointers. Hmmm that will change the SSL_ctrl() behaviour but that shouldn't be called directly anyway. The BIOs are a little more awkward for example we've got BIO_set_info_callback() currently defined as a macro casting the callback to (char *). I'd suggest we use a similar technique and zap the macro. The macros that do this kind of thing want replacing with real functions anyway. It will break binary compatibility but I can't think of any alternative. It shouldn't matter too much anyway. So much has changed since 0.9.4 most application should be recompiled anyway. I can't think of anywhere where we have a stack of function pointers. The EX_DATA stuff has them wrapped up in a strucure. Hmm... I've just had a look, its a plain STACK, not STACK_OF and has no prototypes on the function pointers either. It needs fixing. (SSL_CTX_ctrl, ssl3_ctrl et al. still have a char * argument where they should have a void * -- it's certainly trivial to change that.) Yes thats a legacy from the pre-ANSI days. It, and a few others, should be changed and a few (char *) casts deleted as well. Steve. -- Dr Stephen N. Henson. http://www.drh-consultancy.demon.co.uk/ Personal Email: [EMAIL PROTECTED] Senior crypto engineer, Celo Communications: http://www.celocom.com/ Core developer of the OpenSSL project: http://www.openssl.org/ Business Email: [EMAIL PROTECTED] PGP key: via homepage. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
DEC C for VMS is getting really mean. There's a reason DEC went out of business :-) __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
On Mon, Jan 17, 2000 at 01:06:27AM +0100, Richard Levitte - VMS Whacker wrote: DEC C for VMS is getting really mean. Version 6.2 (latest, as far as I know) spews out a message when a (char *) cast is done to a function pointer and vice versa. Every compiler should print such warnings, such casts are by no means guaranteed to work. It's especially visible in all the places where lh_doall_arg() gets a casted function pointer as last argument (for example, see CRYPTO_mem_leaks_cb() in crypto/mem_dbg.c)... I can imagine using silly things like a struct around the function pointer to get rid of that warning. The function pointer *must* be inside a data object to make such constructs legal, so this is not silly at all. An alternative would be to use unions of a function pointer and a data pointer (casts between different function pointer types are legal, you just have to make sure that you call the function as the same type as it was originally defined -- OpenSSL even fails at this) instead of just a void *, but that's probably more complicated than depositing the function pointer in a struct. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
Richard Levitte - VMS Whacker wrote: DEC C for VMS is getting really mean. Version 6.2 (latest, as far as I know) spews out a message when a (char *) cast is done to a function pointer and vice versa. Guess what it finds a little here and there in OpenSSL? :-) Changing (char *) to (void *) (that has been know to do magic sometimes) doesn't help. Hmmm. Does VMS have an equivalent to shared libraries which can be loaded at runtime? If so how is that handled? There's normally a function in there that has to return a value that can be cast into any function pointer. Steve. -- Dr Stephen N. Henson. http://www.drh-consultancy.demon.co.uk/ Personal Email: [EMAIL PROTECTED] Senior crypto engineer, Celo Communications: http://www.celocom.com/ Core developer of the OpenSSL project: http://www.openssl.org/ Business Email: [EMAIL PROTECTED] PGP key: via homepage. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
DEC C for VMS is getting really mean. Version 6.2 ^^^ It has nothing to do with VMS. It complains about casts between (*) and * even on Unix. It's especially visible in all the places where lh_doall_arg() gets a casted function pointer as last argument (for example, see CRYPTO_mem_leaks_cb() in crypto/mem_dbg.c)... I can imagine using silly things like a struct around the function pointer to get rid of that warning. The function pointer *must* be inside a data object to make such constructs legal, But that's what Richard (subconsciously?) attempted to do in first place: static void (*mem_cb)()=NULL; void CRYPTO_mem_leaks_cb(void (*cb)()) { ... mem_cb=cb; lh_doall_arg(mh,(void (*)())cb_leak,(char *)mem_cb); mem_cb=NULL; ... } I mean someting has prevented him from just "lh_doall_arg(mh,(void (*)())cb_leak,(char *)cb)," hasn't it? so this is not silly at all. An alternative would be to use unions of a function pointer Why structures/unions? "lh_doall_arg(mh,(void (*)())cb_leak,(void *)mem_cb)" should do... Of course provided that it's appropriately derefenced in cb_leak! And I fail to understand why mem_cb has to be declared static? It can be perfectly declared in CRYPTO_mem_leaks_cb scope which also makes it multi-thead safe, doesn't it? To summarize: typedef void (*cb_t) (); static void cb_leak(MEM *m, void *cb) { void (*mem_callback)()=*((cb_t *)cb); mem_callback(m-order,m-file,m-line,m-num,m-addr); } void CRYPTO_mem_leaks_cb(void (*cb)()) { void (*mem_cb)() = cb; if (mh == NULL) return; CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); lh_doall_arg(mh,(void (*)())cb_leak,(void *)(mem_cb)); CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); } Andy. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
bmoeller The function pointer *must* be inside a data object to make bmoeller such constructs legal, so this is not silly at all. Perfectly right. My "silly" wasn't completely serious... Anyway, thanks for the input, it confirmed that my thoughts were right. Time to hack :-). -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
ssampson DEC C for VMS is getting really mean. ssampson ssampson There's a reason DEC went out of business :-) True. However, that's not it. DEC software has had a tendency to hold quite high quality, and it seems that Compaq will keep that. Sorry, but you really shot the wrong dog here... -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
drh Hmmm. Does VMS have an equivalent to shared libraries which can drh be loaded at runtime? drh If so how is that handled? Looks like this: int status = LIB$FIND_FILE_SYMBOL(lib_file, symbol_name, symbol_address, dir_spec, flags); The secret is that LIB$FIND_FILE_SYMBOL is declared as having unknown parameters (...), so you can give it whatever you like in there. The routine is pretty good at checking that the arguments make sense. drh There's normally a function in there that has to return a value drh that can be cast into any function pointer. Doesn't help much in this case, does it ? :-) -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
appro The function pointer *must* be inside a data object to make appro such constructs legal, appro But that's what Richard (subconsciously?) attempted to do in appro first place: Don't look at me, that part of the code was there in mem.c since eons... appro static void (*mem_cb)()=NULL; appro appro void CRYPTO_mem_leaks_cb(void (*cb)()) appro { appro ... appro mem_cb=cb; appro lh_doall_arg(mh,(void (*)())cb_leak,(char *)mem_cb); appro mem_cb=NULL; appro ... appro } appro appro I mean someting has prevented him from just "lh_doall_arg(mh,(void appro (*)())cb_leak,(char *)cb)," hasn't it? I Actually don't know why Eric needed to do that. But just for clarity, let me show you what DEC C says: void (*mem_callback)()=(void (*)())cb; ...^ %CC-I-NONSTANDCAST, In the initializer for mem_callback, "cb" of type "pointer to char", is being converted to "pointer to function () returning void". Such a cast is not permitted by the standard. at line number 668 in file DISK$ALPUTILS:[LEVITTE.WRK.OPENSSL-0_9_5-DEV.CRYPTO]MEM_DBG.C;3 lh_doall_arg(mh,(void (*)())cb_leak,(char *)mem_cb); ^ %CC-I-NONSTANDCAST, In this statement, "mem_cb" of type "pointer to function () returning void", is being converted to "pointer to char". Such a cast is not permitted by the standard. at line number 677 in file DISK$ALPUTILS:[LEVITTE.WRK.OPENSSL-0_9_5-DEV.CRYPTO]MEM_DBG.C;3 As you can see, whatever you do with the current scheme, there will always be a conversion between function pointers and non-function pointers. appro so this is not silly at all. An alternative would be to use appro unions of a function pointer appro Why structures/unions? "lh_doall_arg(mh,(void (*)())cb_leak,(void appro *)mem_cb)" should do... The easiest way to avoid the conversions noted above is to have a union like this: union foo { void *simple; int (*fn)(); }; and use it internally. You put whatever char * you want to convert to a functino pointer into simple and pull out the function pointer from fn, and vice versa. appro Of course provided that it's appropriately derefenced in appro cb_leak! As you can see above, that's exactly one of the problems. appro And I fail to understand why mem_cb has to be declared static? Not to be seen outside of the file? appro It can be perfectly declared in CRYPTO_mem_leaks_cb scope which appro also makes it multi-thead safe, doesn't it? You're absolutely right about, but that is beside the point in this case. This is a ANSI C problem, not a MT problem. appro typedef void (*cb_t) (); appro appro static void cb_leak(MEM *m, void *cb) appro { appro void (*mem_callback)()=*((cb_t *)cb); You convert from void * to void (*)() (i.e. between a "simple type" and a function pointer). DEC C will complain. appro mem_callback(m-order,m-file,m-line,m-num,m-addr); appro } appro appro void CRYPTO_mem_leaks_cb(void (*cb)()) appro { appro void (*mem_cb)() = cb; appro if (mh == NULL) return; appro CRYPTO_w_lock(CRYPTO_LOCK_MALLOC2); appro lh_doall_arg(mh,(void (*)())cb_leak,(void *)(mem_cb)); You convert from void (*)() to void * (i.e. between a "simple type" and a function pointer). DEC C will complain. appro CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC2); appro } -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
BTW, I just discovered the following (about crypto/x509v3/v3_int.c): (X509V3_EXT_S2I)NULL, ^ %CC-I-NONSTANDCAST, In the initializer for v3_crl_num.s2i, "((void ...)0)" of type "pointer to void", is being converted to "pointer to function (pointer to struct v3_ext_method, pointer to struct v3_ext_ctx, pointer to char) returning pointer to void". Such a cast is not permitted by the standard. at line number 70 in file DISK$ALPUTILS:[LEVITTE.WRK.OPENSSL-0_9_5-DEV.CRYPTO.X509V3]V3_INT.C;1 that hurt... -- Richard Levitte \ Spannvägen 38, II \ [EMAIL PROTECTED] Redakteur@Stacken \ S-161 43 BROMMA \ T: +46-8-26 52 47 \ SWEDEN \ or +46-708-26 53 44 Procurator Odiosus Ex Infernis -- [EMAIL PROTECTED] Unsolicited commercial email is subject to an archival fee of $400. See http://www.stacken.kth.se/~levitte/mail/ for more info. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]
Re: Sadistic C compiler...
And more text: 5.6.2 Function and Array Identifiers as Arguments Function and array identifiers can be specified as argu- ments to a function. Function identifiers are specified without parentheses, and array identifiers are specified without brackets. When so specified, the function or array identifier is evaluated as the address of that function or array. Also, the function must be declared or defined, even if its return value is an integer. Example 5-1 shows how and when to declare functions passed as arguments, and how to pass them. Key to Example 5-1: 1 Without being declared in a separate declaration, function x can be passed in an argument list because its defi- nition, located before the function caller, serves as its declaration. 2 Parameters that represent functions can be declared ei- ther as functions or as pointers to functions. Parameters that represent arrays can be declared either as arrays or as pointers to the element type of the array. For example: fn(int f1(), int f2(), int a1[]) /* f1, f2 declared as */ {...}/* functions; a1 declared */ /* as array of int. */ fn(int (*f1)(), int (*f2)(), int *a1) /* f1, f2 declared as */ {...}/* pointers to functions; */ /* a1 declared as pointer */ /* to int. */ When such parameters are declared as functions or arrays, the compiler automatically converts the corre- sponding arguments to pointers. 3 Because its function definition is located after the function caller, function y must be declared before passing it in an argument list. 4 When passing functions as arguments, do not include parentheses. Similarly, when specifying arrays, do not include subscripts. Example 5-1: Declaring Functions Passed as Arguments 1 int x() { return 25; } /* Function definition and */ int z[10];/* array defined before use */ 2 fn(int f1(), int (*f2)(), int a1[])) /* Function definition */ { f1(); /* Call to function f1 */ . . . } void caller(void) { 3 int y(); /* Function declaration */ . . . 4 fn(x, y, z);/* Function call: functions */ /* x and y, and array z */ /* passed as addresses */ . . . } int y(void) { return 30; } /* Function definition */ 6.11.2 Pointer Conversions Although two types (for example,int and long) can have the same representation, they are still different types. This means that a pointer to int cannot be assigned to a pointer to long without using a cast. Nor can a pointer to a func- tion of one type be assigned to a pointer to a function of a different type without using a cast. In addition, pointers to functions that have different parameter-type information, including the old-style absence of parameter-type informa- tion, are different types. In these instances, if a cast is not used, the compiler issues an error. Because there are align- ment restrictions on some target processors, access through an unaligned pointer can result in a much slower access time or a machine exception. A pointer to void can be converted to or from a pointer to any incomplete or object type. If a pointer to any incomplete or object type is converted to a pointer to void and back, the result compares equal to the original pointer. An integral constant expression equal to 0, or such an expres- sion cast to thevoid * type, is called anull pointer constant. If a null pointer constant is assigned to or compared for equality with a pointer, the constant is converted to a pointer of that type. Such a pointer is called anull pointer, and is guaranteed to compare unequal to a pointer to any object or function. An array designator is automatically converted to a pointer to the array type, and the pointer points to the first element of the array. Jeffrey Altman * Sr.Software Designer * Kermit-95 for Win32 and OS/2 The Kermit Project * Columbia University 612 West 115th St #716 * New York, NY * 10025 http://www.kermit-project.org/k95.html * [EMAIL PROTECTED] __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager
Re: Sadistic C compiler...
Andy Polyakov [EMAIL PROTECTED]: The function pointer *must* be inside a data object to make such constructs legal, But that's what Richard (subconsciously?) attempted to do in first place: static void (*mem_cb)()=NULL; void CRYPTO_mem_leaks_cb(void (*cb)()) { ... mem_cb=cb; lh_doall_arg(mh,(void (*)())cb_leak,(char *)mem_cb); mem_cb=NULL; ... } That's weird, I did not notice this and don't know why he did it this way (and probably he doesn't either :-). This is however not what I meant, this is just like calling lh_doall_arg(mh,(void (*)())cb_leak,(char *)cb); without using the extra static variable. We're still passing a function pointer value. What would work, however, is void CRYPTO_mem_leaks_cb(void (*cb)()) { ... void *cb_ptr=cb; lh_doall_arg(mh,(void (*)())cb_leak,cb); ... } (there's no reason to introduce a struct unless one wants to do things over-complicated, I don't know why I mentioned structs before). The point is that C doesn't like mixing function pointers and data object pointers; they don't necessarily have identical representations (you could have 32 bit function pointers, but 64 bit data pointers). To force C to convert values between these types, you'd have to cast to some integer type inbetween: (void (*)()) (long) cb But of course this is so complicated because it should never be done and is not guaranteed to do anything useful. cb, on the other hand, is the pointer to some data object; the function that gets this pointer as an argument has to retrieve the actual function pointer from inside this data object, i.e. use *((void (**)()) arg) where arg is the void * argument passed to it. __ OpenSSL Project http://www.openssl.org Development Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]