> appro> > Why pass a reference?  C has been able to pass&return 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]

Reply via email to