Re: OpenSSL breaks with gcc 4.2

2006-11-13 Thread Dr. Stephen Henson
On Fri, Nov 10, 2006, Dr. Stephen Henson wrote:

 
 OK, looks like inline calls is the way to go. Those at least have some
 advantages over the existing stuff.
 

For gcc (4.0, 4.2 at least on X86) it looks like it will translate equivalent
(at a machine level) function calls into a single jump instruction with -O3
-fomit-frame-pointer.

In the inline case will optimize away the call entirely so that a call to
sk_X509_new_null() ends up outputting identical code to sk_new_null().

It will not do the same for function pointers however so passing
sk_X509_new_null() as an fp doesn't end up passing sk_new_null().

So it seems that at least on these platforms doing the right thing will have
minimal overhead.

Steve.
--
Dr Stephen N. Henson. Email, S/MIME and PGP keys: see homepage
OpenSSL project core developer and freelance consultant.
Funding needed! Details on homepage.
Homepage: http://www.drh-consultancy.demon.co.uk
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-10 Thread David Schwartz

 The equivalent of the offending line would be
 
 foo((double *)(void *) j);
 
 since any access through a void pointer CAN change the value.

'(double *)(void *)' does not keep some sort of remnant of the 'void *'. The 
final cast renders the end-result a 'double *' and negates the 'void *'. You 
cannot cast 'through' another type to get some remnant of that type. (In old C.)

This is a very common 'fix' for aliasing bugs that does not work.
 
 Thank you for showing me why I should always include
 -fno-strict-aliasing in my gcc commandlines.  It's broken, horribly.

Actually, what's broken is not allowing a large class of useful optimizations 
for the occasional code that chooses to invoke undefined behavior. That said, I 
do exactly what you suggest. I've had too much old code break horribly and 
subtly to find the optimizations worth the risk. So my 'official' position is 
not the same as my personal position.

C has unions and 'char *', and more recently 'void *'. However, you cannot 
invoke them and then discard them and expect some 'remnant'. An object is the 
type of the last cast.

I'm going to go dig out my standard. Maybe I'm misremembering.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-10 Thread Kyle Hamilton

An object may be the type of its last cast -- but it also can't
exactly lose the benefit/cost of being cast to a pointer to an
undefined type.  As soon as you undefine the type of a pointer, it
loses the remnant of ever having had the initial type in the first
place.

In KR C, you couldn't cast to void *, that was first introduced in
C89.  You had to cast to char *, and then you could cast to some other
type in order to make your array indexes jump sizeof(type),
essentially (on 8-bit byte machines) referencing
array[(index)*(sizeof(type))].

On 11/10/06, David Schwartz [EMAIL PROTECTED] wrote:


 The equivalent of the offending line would be

 foo((double *)(void *) j);

 since any access through a void pointer CAN change the value.

'(double *)(void *)' does not keep some sort of remnant of the 'void *'. The 
final cast renders the end-result a 'double *' and negates the 'void *'. You 
cannot cast 'through' another type to get some remnant of that type. (In old C.)


(double *)(void *) can't keep any sort of remnant of the int, as it
becomes never-was-an-int-at-all via the (void *) cast.

It's also illegal to take the address of a register, which destroys
the entire concept of aliasing in the first place -- core has always
been core, and any operation can be performed on any part of core
(with the proviso that the machine code generated by the C compiler
must assure proper alignment for the processor).  Trying to treat any
piece of core as anything other than a union of all possible types
(since it can't be a struct, because structs take up more memory to be
able to do what they do, and that violates the assumptions on which
the string library depends, among others) is completely foolhardy, and
gives rise to a situation which would more properly be in the domain
of 'pedantic'.


 Thank you for showing me why I should always include
 -fno-strict-aliasing in my gcc commandlines.  It's broken, horribly.

Actually, what's broken is not allowing a large class of useful optimizations 
for the occasional code that chooses to invoke undefined behavior. That said, I 
do exactly what you suggest. I've had too much old code break horribly and 
subtly to find the optimizations worth the risk. So my 'official' position is 
not the same as my personal position.


'occasional'?  I've never examined any substantial program in C that
doesn't invoke that -- even if just to be able to read data from disk
into memory.


C has unions and 'char *', and more recently 'void *'. However, you cannot 
invoke them and then discard them and expect some 'remnant'. An object is the 
type of the last cast.

I'm going to go dig out my standard. Maybe I'm misremembering.

DS


An object is the type of the last cast -- but if it's ever cast to
void *, it must be treated as if it were never any type before that.
This may have changed in C99, but I'd really much rather have the
option of selecting which dialect I'm using, if only because code that
does work will suddenly not work if compiled with a new dialect.  (Is
the word 'father' or 'goat'?  I can't tell...)

-Kyle H
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-10 Thread David Schwartz

I found the rule -- at least for C99. It is ISO 9899:1999 section 
6.2.5, rule 26 and footnote 39:

26) A pointer to void shall have the same representation and alignment 
requirements as a
pointer to a character type. Similarly, pointers to qualified or unqualified 
versions of compatible types shall have the same representation and alignment 
requirements. All
pointers to structure types shall have the same representation and alignment 
requirements
as each other. All pointers to union types shall have the same representation 
and
alignment requirements as each other. Pointers to other types need not have the 
same representation or alignment requirements.

39) The same representation and alignment requirements are meant to imply 
interchangeability as arguments to functions, return values from functions, and 
members of unions.

This means you cannot pass an 'X509 **' as a 'char **'. Unfortunately 
'X509 *' and 'char *' are not compatible types because 'X509' and 'char' are 
not compatible. They are not both unions, they are not both structures.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-10 Thread David Schwartz

 An object may be the type of its last cast -- but it also can't
 exactly lose the benefit/cost of being cast to a pointer to an
 undefined type.  As soon as you undefine the type of a pointer, it
 loses the remnant of ever having had the initial type in the first
 place.

Right, but that doesn't help you. For example:

int j=2;
double *d=(double *)(void *)j;
*d=1.0;
printf(%d\n, j);

This can output 2. Even though 'j' lost all intness by the cast to 'void *', 
it got 100% doubleness by the cast to 'double *'. The compiler can still assume 
that '*d' will not affect the value of 'j' because 'd' is a pointer to a type 
that is incompatible with 'j's type.

The rule still stands -- a modification through a pointer to one type can be 
assumed not to change the value of a variable of an incompatible type.

This is still what OpenSSL does when it passes an 'X509 **' as a 'char **'.
 
 In KR C, you couldn't cast to void *, that was first introduced in
 C89.  You had to cast to char *, and then you could cast to some other
 type in order to make your array indexes jump sizeof(type),
 essentially (on 8-bit byte machines) referencing
 array[(index)*(sizeof(type))].

The cast to 'char *' made things safe. However, once you cast it away from 
'char *', it became dangerous again. There was no remnant of the 'char *' cast. 
Yes, while it was a 'char *', it could alias anything, but as soon as you cast 
it to something else, it can no longer legally alias an incompatible type.

However, it should be safe to pass a 'char *' to a function that takes a 'char 
*', and cast that parameter back to its real value in the function. For 
example, this should be legal:

int inc(int is_double, char *pointer)
{
 if(is_double)
 {
  double *p=(double *) pointer;
  *p=*p+1;
 }
 else
 {
  int *p=(int *) pointer;
  *p=*p+1;
 }
 return 0;
}

---

int inc()
double j=1.0;
int i=to_int(1, (char *) j);
printf(%f, j);

That is because you are passing the function a compatible type, the compiler 
must assume a 'char *' might alias anything, and you are only dereferencing the 
pointer as a compatible type.

 Actually, what's broken is not allowing a large class of useful 
 optimizations for the occasional code that chooses to invoke 
 undefined behavior. That said, I do exactly what you suggest. 
 I've had too much old code break horribly and subtly to find the 
 optimizations worth the risk. So my 'official' position is not 
 the same as my personal position.
 
 'occasional'?  I've never examined any substantial program in C that
 doesn't invoke that -- even if just to be able to read data from disk
 into memory.

Many programs do aliasing correctly, following the rules that permit pointers 
to alias. However, I think it's a very fair point that nobody seems to totally 
understand what the rules *are*, which makes it hard to be sure you're 
following them.
 
 An object is the type of the last cast -- but if it's ever cast to
 void *, it must be treated as if it were never any type before that.

The problem is precisely that it loses its association with the type it first 
was! If it kept its association with the first type, there'd be no problem.

Look at this code again:

int j=2;
double *d=(double *)(void *)j;
*d=1.0;
printf(%d\n, j);

The *problem* is that 'j' has list its intness.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-10 Thread Richard Salz
This means you cannot pass an 'X509 **' as a 'char **'. 
 Unfortunately 'X509 *' and 'char *' are not compatible types because
 'X509' and 'char' are not compatible. They are not both unions, they
 are not both structures.

But you can pass 'X509 **' as 'void *'.  So...
void x509func(void* p) { X509** pp = (X509**)p; ... }
void trampoline(void* p) { x509func(p); }
void caller(void) { X509* p; trampoline(p); }

should (MUST?) work just fine.

/r$

--
STSM, Senior Security Architect
SOA Appliances
Application Integration Middleware

__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-10 Thread David Schwartz

 But you can pass 'X509 **' as 'void *'.  So...
 void x509func(void* p) { X509** pp = (X509**)p; ... }
 void trampoline(void* p) { x509func(p); }
 void caller(void) { X509* p; trampoline(p); }

 should (MUST?) work just fine.

 /r$

When I change my test programs from 'float *' to either 'void *' or 'char
*', the warning goes away. I believe this is completely safe.

So long as the pointer is a 'char *' or a 'void *' at the point of
contention, you are fine. A union would also work. (Whether you use a real
union with a pointer to every possible type or a bogus union containing just
a 'char **'.

The Linux kernel contains stuff like this:

/*
 * Make sure gcc doesn't try to be clever and move things around
 * on us. We need to use _exactly_ the address the user gave us,
 * not some alias that contains the same information.
 */
typedef struct { volatile int counter; } atomic_t;

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-10 Thread Roumen Petrov

David Schwartz wrote:


An object may be the type of its last cast -- but it also can't
exactly lose the benefit/cost of being cast to a pointer to an
undefined type.  As soon as you undefine the type of a pointer, it
loses the remnant of ever having had the initial type in the first
place.
   



Right, but that doesn't help you. For example:

int j=2;
double *d=(double *)(void *)j;
*d=1.0;
printf(%d\n, j);

This can output 2. Even though 'j' lost all intness by the cast to 'void *', 
it got 100% doubleness by the cast to 'double *'. The compiler can still assume 
that '*d' will not affect the value of 'j' because 'd' is a pointer to a type that 
is incompatible with 'j's type.

The rule still stands -- a modification through a pointer to one type can be 
assumed not to change the value of a variable of an incompatible type.

This is still what OpenSSL does when it passes an 'X509 **' as a 'char **'.
 


Are you sure that problem is in cast ?

$ cat test.c
main() {
int j=2;
double *d=(double*)j;
*d=1.0;
printf(%d %e\n, j, *d);
printf(%d %e\n, j, *d);
}
gcc -O2 test.c  ./a.out
2 1.00e+00
0 1.00e+00

Same result in case with line double *d=j; (but expected warning: 
initialization from incompatible pointer type) and double 
*d=(double*)(void*)j;



Thanks to point side effect of -O2 in gcc.

May be is related to -fstrict-aliasing.
The above code we can found in gcc documentation for -fstrict-aliasing.

More results:
$ gcc -O2 -fno-strict-aliasing test.c  ./a.out
0 1.00e+00
0 1.00e+00
$ gcc -O1 -fstrict-aliasing test.c  ./a.out
0 1.00e+00
0 1.00e+00


[SNIP]
 


It seem to me that all examples by David show noting related to the casts.
They only show problem by gcc -O2 .


Roumen

__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-10 Thread David Schwartz

 Are you sure that problem is in cast ?

 $ cat test.c
 main() {
 int j=2;
 double *d=(double*)j;
 *d=1.0;
 printf(%d %e\n, j, *d);
 printf(%d %e\n, j, *d);
 }
 gcc -O2 test.c  ./a.out
 2 1.00e+00
 0 1.00e+00

 Same result in case with line double *d=j; (but expected warning:
 initialization from incompatible pointer type) and double
 *d=(double*)(void*)j;

No, the problem is not in the cast. The problem is that the cast doesn't
save you when you think it does. Without the cast, you are equally screwed,
it's just that it's obvious you deserve it in that case. ;)

 It seem to me that all examples by David show noting related to the casts.
 They only show problem by gcc -O2 .

The problem is that the casts don't do what people think they do and that
GCC assumes code obeys the standard.

With or without the cast, the compiler has every right to assume that a
modification to the thing a 'double *' points to won't change the value of
an integer. The exception would be code that uses the specifically allowed
aliasing techniques, such as unions and pointers to characters.

It's just that compilers haven't previously been smart enough to make these
kinds of  optimizations. Now they are, so we'll have to either follow the
standard or disable the optimizations. Which option is a judgment call. I
generally try to do both out of abundance of caution.

The argument is that code that does this is rare enough and the
optimizations valuable enough that it's worth making everyone fix their code
to follow the aliasing rules. The counter-argument is that experts don't
agree on what the aliasing rules *are*, so how are mere mortals supposed to
follow them?

This is separate from the issue of calling a function with an incompatible
pointer type, which is also a violation of the standard.

There may be problems with newer versions of GCC even for code that complies
with all the parameter passing and aliasing rules, but I haven't seen it.
Does anyone know if turning off strict aliasing and changing the functions
to take 'char *'s solves the problem?

I might be able to run some tests myself in a few hours.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Ben Laurie
Richard Levitte - VMS Whacker wrote:
 In message [EMAIL PROTECTED] on Wed, 8 Nov 2006 21:59:19 -0800, David 
 Schwartz [EMAIL PROTECTED] said:
 
 davids You are correct, but that's not the issue. The issue is this
 davids simple -- if you are going to call a function whose types you
 davids don't know (through a prototype), you must cast each type you
 davids pass to the type the function expects. End of story. OpenSSL
 davids does not do this. This is not valid C whether or not the type
 davids sizes are the same.
 
 So basically, you're saying that KR-style functions (non-prototyped)
 aren't handled in a pre-prototype manner any more?  That's a fairly
 extreme change of how C used to work.  While I understand such a
 change, it's going to break quite a lot of things that still have
 non-prototyped functions.
 
 Can you provide something in the C standard that supports this change?

Clearly this argument only applies to prototyped functions.

-- 
http://www.apache-ssl.org/ben.html   http://www.links.org/

There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit. - Robert Woodruff
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Ben Laurie
David Schwartz wrote:
 x is still just a pointer to data - so it's the same
 length in any case, all pointers to lvalues are the
 same length in C. The only issue there is whether it's
 aligned correctly - that's the programmers problem.
 
 Length is not the issue. There is no rule that says that two types must be
 passed the same way just because they're the same length. For example, some
 platforms may pass a 64-bit floating point number in a floating point
 register but pass a 64-bit integer in an integer register.
 
 All you can do is assume that it will work because it has always worked,
 until it stops working.
 
 Mixing something like char *(*d2i)(), and char ** IS
 problematic, since those aren't guaranteed to be the
 same length but as far as I can remember OpenSSL doesn't
 do that.
 
 If they are not the same length, it is not likely to work. That doesn't mean
 it's legal if they are the same length.
 
 ret=d2i(x,p,len);
 
 d2i is a function (prototype is unknown)
 but I've been told  x is a pointer, p is a pointer,
 len is long. There's nothing indeterminate about the
 size of any of those.
 
 The issue is not size, it's type.
 
 C isn't a strongly typed language - there's no language
 requirement for an accurate function prototype or that
 the types of the arguments be correct - only that the
 size of them is correct.
 
 You are correct, but that's not the issue. The issue is this simple -- if
 you are going to call a function whose types you don't know (through a
 prototype), you must cast each type you pass to the type the function
 expects. End of story. OpenSSL does not do this. This is not valid C whether
 or not the type sizes are the same.
 
 C is not the same language as C++, this instance should
 work with a C compiler - whether or not the compiler is
 passing the arguments via the stack or in registers.
 
 Can you cite anything in the C standard that says this is allowed? As I
 understand it, you must pass a function precisely the types it expects, or
 use a prototype to force the compiler to cast them. Either way, the exact
 type must be known where the call is compiled.

It appears to me, then, that the consequence of this is that we can't
have type-safety and generic functions. This strikes me as a huge pain
in the ass. Surely there's some way around it?

-- 
http://www.apache-ssl.org/ben.html   http://www.links.org/

There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit. - Robert Woodruff
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Peter Waltenberg

Length is not the issue. There is no rule that says that two types must be
passed the same way just because they're the same length. For example, some
platforms may pass a 64-bit floating point number in a floating point
register but pass a 64-bit integer in an integer register.


I'm not sure that's true, it's an optimization sure, but C doesn't care
about type. So there are optimizations that aren't legal for the C
language.
In this case I can't see a problem.
Sure if you were passing either a float or a long, which happened to be the
same size and you had a dedicated FPU register I can see a problem, (though
I suspect even in this case the optimzation is dubious for C ) but in this
case the ambiguity is at the thing the pointer points to. Any optimization
here would be in the called function - either loading the thing the pointer
points to into an integer or FPU register. They can't have separate address
spaces or this would be impossible:

typedef struct {
  float f;
  long l;
  } X;


You are correct, but that's not the issue. The issue is this simple -- if
you are going to call a function whose types you don't know (through a
prototype), you must cast each type you pass to the type the function
expects. End of story. OpenSSL does not do this. This is not valid C
whether
or not the type sizes are the same.


Sorry, I think it's a compiler bug. The compiler DOES know the types of the
arguments in every case, it's what they are declared to be by default, it
even has the information necessary to decide the register the arguments
should be passed in (WRT to the FPU register argument above.)
Yes the programmer *might* have screwed up, but that's not the compiler
writers call. Emit a warning by all means but this is resolvable at compile
time.

And saying it's the compilers job to catch this is bogus as well, I can
cast the function to the wrong type and cause exactly the problems at
runtime that this optimization is supposed to protect against.


Can you cite anything in the C standard that says this is allowed? As I
understand it, you must pass a function precisely the types it expects, or
use a prototype to force the compiler to cast them. Either way, the exact
type must be known where the call is compiled.


printf() still works and that disagrees with your view of the universe.

And as noted above, the function is prototyped, just not explicitly,
assuming the programmer got the argument types correct and the type of the
variable holding the return value you have an implicit (and sufficient)
function prototype.
You can't have no function prototype at all at the point you make the call
in C. Yes, you can get it wrong and crash, but historically that's been the
programmers responsibility.

Your argument IS valid for C++, but I'm not yet convinced it's correct for
C.

Peter

https://cs.opensource.ibm.com/projects/icc



   
 David Schwartz  
 [EMAIL PROTECTED] 
 .com  To 
 Sent by:  openssl-dev@openssl.org   
 owner-openssl-dev  cc 
 @openssl.org  
   Subject 
   RE: OpenSSL breaks with gcc 4.2 
 09/11/06 03:59 PM 
   
   
 Please respond to 
openssl-dev
   
   





 x is still just a pointer to data - so it's the same
 length in any case, all pointers to lvalues are the
 same length in C. The only issue there is whether it's
 aligned correctly - that's the programmers problem.

Length is not the issue. There is no rule that says that two types must be
passed the same way just because they're the same length. For example, some
platforms may pass a 64-bit floating point number in a floating point
register but pass a 64-bit integer in an integer register.

All you can do is assume that it will work because it has always worked,
until it stops working.

 Mixing something like char *(*d2i)(), and char ** IS
 problematic, since those aren't guaranteed to be the
 same length but as far as I can remember OpenSSL doesn't
 do that.

If they are not the same length, it is not likely to work. That doesn't
mean
it's legal if they are the same length.

 ret

Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Richard Salz
 davids simple -- if you are going to call a function whose types you
 davids don't know (through a prototype), you must cast each type you
 davids pass to the type the function expects. End of story. OpenSSL
 davids does not do this. This is not valid C whether or not the type
 davids sizes are the same.

I don't think that's correct.  If you are calling a function where a 
prototype is not in scope, the 'classic' promotion rules are used (float 
to double, char or short to int, etc).

/r$

--
STSM, Senior Security Architect
SOA Appliances
Application Integration Middleware

__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Dr. Stephen Henson
On Thu, Nov 09, 2006, Richard Salz wrote:

  davids simple -- if you are going to call a function whose types you
  davids don't know (through a prototype), you must cast each type you
  davids pass to the type the function expects. End of story. OpenSSL
  davids does not do this. This is not valid C whether or not the type
  davids sizes are the same.
 
 I don't think that's correct.  If you are calling a function where a 
 prototype is not in scope, the 'classic' promotion rules are used (float 
 to double, char or short to int, etc).
 

Well just to add to the confusion... I've compiled up gcc4.2 myself from
source just to see what is going on.

Yes it does indeed give the reported issues but what is strange is that almost
identical constructs (the safestack, and some related macros) don't even
generate a warning.

Steve.
--
Dr Stephen N. Henson. Email, S/MIME and PGP keys: see homepage
OpenSSL project core developer and freelance consultant.
Funding needed! Details on homepage.
Homepage: http://www.drh-consultancy.demon.co.uk
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Stephen Sprunk

Thus spake Peter Waltenberg
x is still just a pointer to data - so it's the same length in any 
case, all

pointers to lvalues are the same length in C. The only issue there is
whether it's aligned correctly - that's the programmers problem.


It's not the only problem.

Mixing something like char *(*d2i)(), and char ** IS problematic, 
since

those aren't guaranteed to be the same length but as far as I can
remember OpenSSL doesn't do that.

ret=d2i(x,p,len);

d2i is a function (prototype is unknown)
but I've been told  x is a pointer, p is a pointer, len is long. 
There's

nothing indeterminate about the size of any of those.


Incorrect.  When the compiler encounters this statement, if there's no 
prototype for d2i() in scope, it is _required_ to act as if the 
prototype were:


int d2i(int, int, int);

Since you're passing two pointers and a long, this is simply invalid. 
It may work on some platforms, but it's undefined behavior and a 
compiler is free to do whatever it wants (including insert code to crash 
the program).


C isn't a strongly typed language - there's no language requirement 
for

an accurate function prototype or that the types of the arguments be
correct - only that the size of them is correct.


C89 had already deprecated non-prototyped functions.  In C99, they're 
prohibited, so there is a requirement today.



C is not the same language as C++, this instance should work with a
C compiler - whether or not the compiler is passing the arguments via
the stack or in registers.


Again, not correct.  There are implementations that pass ints, longs, 
and pointers all in different registers.  Some platforms have specific 
registers for pointers, just like many have specific registers for 
floats/doubles.  Others will have the top half of a long corrupted if 
sizeof(long)sizeof(int), which is common on many 64-bit machines.


S

Stephen Sprunk God does not play dice.  --Albert Einstein
CCIE #3723 God is an inveterate gambler, and He throws the
K5SSSdice at every possible opportunity. --Stephen Hawking


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Richard Salz
 Incorrect.  When the compiler encounters this statement, if there's no 
 prototype for d2i() in scope, it is _required_ to act as if the 
 prototype were:
 
 int d2i(int, int, int);

This is wrong.  The usual integral promotions apply -- but only to 
integral parameters, not to ALL of them.

/r$


--
STSM, Senior Security Architect
SOA Appliances
Application Integration Middleware

__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Ken Ballou
Stephen Sprunk wrote:
 Thus spake Peter Waltenberg
 x is still just a pointer to data - so it's the same length in any
 case, all
 pointers to lvalues are the same length in C. The only issue there is
 whether it's aligned correctly - that's the programmers problem.
 
 It's not the only problem.
 
 Mixing something like char *(*d2i)(), and char ** IS problematic, since
 those aren't guaranteed to be the same length but as far as I can
 remember OpenSSL doesn't do that.

 ret=d2i(x,p,len);

 d2i is a function (prototype is unknown)
 but I've been told  x is a pointer, p is a pointer, len is long. There's
 nothing indeterminate about the size of any of those.
 
 Incorrect.  When the compiler encounters this statement, if there's no
 prototype for d2i() in scope, it is _required_ to act as if the
 prototype were:
 
 int d2i(int, int, int);

I believe this is incorrect.  When there is no prototype in scope, I
believe the compiler is _required_ to act as though there is a prototype
that exactly matches the type and number of arguments in the function
call after applying the usual arithmetic promotions.  (I believe the
intent was to preserve compatibility with old pre-prototype KR code.
Assuming that all parameters are of type int would wreak havoc with old
code, no?)

- Ken
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-09 Thread David Schwartz

  davids simple -- if you are going to call a function whose types you
  davids don't know (through a prototype), you must cast each type you
  davids pass to the type the function expects. End of story. OpenSSL
  davids does not do this. This is not valid C whether or not the type
  davids sizes are the same.

 I don't think that's correct.  If you are calling a function where a
 prototype is not in scope, the 'classic' promotion rules are used (float
 to double, char or short to int, etc).

 /r$

Are you saying the call is legal even if the promotion rules do not result
in calling the function with the exact types it expects? That conflicts
massively with my understanding of the C language.

As I understood it, calling a function without a prototype was precisely
equivalent to declaring a prototype of the function with the exact parameter
types passed (after promotion rules).

Calling a function with the wrong pointer type *will* break in the face of
optimization. That is why GCC 4.2 breaks when it tries to inline such
function calls. Even if it wasn't a violation of C's function type rules,
which I think it is, it's also a violation of C's aliasing rules (when the
types are pointers).

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Dr. Stephen Henson
On Thu, Nov 09, 2006, Dr. Stephen Henson wrote:

 On Thu, Nov 09, 2006, Richard Salz wrote:
 
   davids simple -- if you are going to call a function whose types you
   davids don't know (through a prototype), you must cast each type you
   davids pass to the type the function expects. End of story. OpenSSL
   davids does not do this. This is not valid C whether or not the type
   davids sizes are the same.
  
  I don't think that's correct.  If you are calling a function where a 
  prototype is not in scope, the 'classic' promotion rules are used (float 
  to double, char or short to int, etc).
  
 
 Well just to add to the confusion... I've compiled up gcc4.2 myself from
 source just to see what is going on.
 
 Yes it does indeed give the reported issues but what is strange is that almost
 identical constructs (the safestack, and some related macros) don't even
 generate a warning.
 

Which was mainly due to me not having the right versions of the safestack
macros enabled but hey, its been a long week :-)

Hmmm nasty. It will tolerate function pointer casting if a variable is used
but I suspect that's more because the optimizer hasn't yet learned to stamp
on it.

OK, looks like inline calls is the way to go. Those at least have some
advantages over the existing stuff.

Steve.
--
Dr Stephen N. Henson. Email, S/MIME and PGP keys: see homepage
OpenSSL project core developer and freelance consultant.
Funding needed! Details on homepage.
Homepage: http://www.drh-consultancy.demon.co.uk
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Richard Salz
 As I understood it, calling a function without a prototype was precisely
 equivalent to declaring a prototype of the function with the exact 
parameter
 types passed (after promotion rules).

Nope.  Calling a function without a prototype is precisely equivalent to 
KR rules.  If a function will be called in such KR style, and the 
function prototype and/or definition have any non-promoted parameters, the 
result is undefined.  For example
void foo(short p1) {  }
is *ILLEGAL* if foo will ever be called without a prototype in scope; p1 
must be an int.

 Calling a function with the wrong pointer type *will* break in the face 
of
 optimization. That is why GCC 4.2 breaks when it tries to inline such
 function calls. Even if it wasn't a violation of C's function type 
rules,
 which I think it is, it's also a violation of C's aliasing rules (when 
the
 types are pointers).

Once KR is included, the situation becomes a lot less clear.  Also, as I 
read the thread on the GCC list, it looks like the situation is further 
complicated by their desire to avoid an internal compiler error.  Also**2, 
I don't know what you mean by C's aliasing rules; to me that brings to 
mind the ill-conceived 'noalias' qualifier.

If this is worth further discussion, a concrete example (code fragment) 
would help me a lot.

/r$

--
STSM, Senior Security Architect
SOA Appliances
Application Integration Middleware

__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-09 Thread David Schwartz

 Once KR is included, the situation becomes a lot less clear.  Also, as I
 read the thread on the GCC list, it looks like the situation is further
 complicated by their desire to avoid an internal compiler error.
 Also**2,
 I don't know what you mean by C's aliasing rules; to me that brings to
 mind the ill-conceived 'noalias' qualifier.

 If this is worth further discussion, a concrete example (code fragment)
 would help me a lot.

 /r$

What I mean by aliasing rules is that with only a few exceptions, a compiler
is allowed to assume that an access through a pointer of one type cannot
affect the value of a variable of a different type.

GCC's optimization in this area has gotten to the point where it bites a lot
of people, and I think it's the aliasing issue that's the problem for
OpenSSL, not really the function prototype issue. Right now, the GCC bug
with the most duplicates is due to aliasing errors.

The GCC not a bug page gives this example:

int main()
{
  short a[2];

  a[0]=0x;
  a[1]=0x;

  *(int *)a = 0x; /* violation of aliasing rules */

  printf(%x %x\n, a[0], a[1]);
  return 0;
}

The compiler has every right to print  and , because under C rules,
no modification to an integer can change the value of a short.

However, this is also an example:

extern void foo();
int main(void)
{
 int j=2;
 foo((double *) j);
 printf(%d\n, j);
 return 0;
}

The compiler has every right to assume that 'j' still has the value '2' in
the 'printf' call because 'j' is local to 'main' and no modification through
a 'double *' pointer can possibly change the value of an 'int'.

GCC 403 warns about this (with flags: -O3 -Wall)
test.c:9: warning: dereferencing type-punned pointer will break
strict-aliasing rules
Line 9 is the call to 'foo'.

OpenSSL's PEM #define's do the same thing as this example.

However, if OpenSSL fixes its aliasing issues and *still* has a problem,
then I think you can complain to the GCC guys. I think the current GCC issue
can be tripped even in code which doesn't violate aliasing rules, but I
think you still have to violate the parameter passing rules.

So either way, it's not GCC's fault strictly speaking. Though GCC's behavior
is suboptimal, certainly. GCC will take care of its problems, but OpenSSL
should take care of its problems too. A lot of older code is getting bitten
by compilers that more heavily optimize and break code that uses illegal
type-punning.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-09 Thread Kyle Hamilton

On 11/9/06, David Schwartz [EMAIL PROTECTED] wrote:


 Once KR is included, the situation becomes a lot less clear.  Also, as I
 read the thread on the GCC list, it looks like the situation is further
 complicated by their desire to avoid an internal compiler error.
 Also**2,
 I don't know what you mean by C's aliasing rules; to me that brings to
 mind the ill-conceived 'noalias' qualifier.

 If this is worth further discussion, a concrete example (code fragment)
 would help me a lot.

 /r$

What I mean by aliasing rules is that with only a few exceptions, a compiler
is allowed to assume that an access through a pointer of one type cannot
affect the value of a variable of a different type.

GCC's optimization in this area has gotten to the point where it bites a lot
of people, and I think it's the aliasing issue that's the problem for
OpenSSL, not really the function prototype issue. Right now, the GCC bug
with the most duplicates is due to aliasing errors.

The GCC not a bug page gives this example:

int main()
{
  short a[2];

  a[0]=0x;
  a[1]=0x;

  *(int *)a = 0x; /* violation of aliasing rules */

  printf(%x %x\n, a[0], a[1]);
  return 0;
}

The compiler has every right to print  and , because under C rules,
no modification to an integer can change the value of a short.


Ummm... could you please cite where in the standard (and which
standard within which) you're seeing that?  That is completely
opposite of how every compiler I've ever used, across seven OSes and
five platforms, has acted -- and I would argue that it makes no sense.
Any memory location (pointer) can be seen as different things,
depending on the cast that is used.  If you're worried, you can look
at the *(int a) = 0x as creating a const qualifier, but even
then the issue becomes murky -- if the pointer is cast to (void *) and
passed to another function, then the called function has no idea what
to look at it as without extra context, which could be wildly
inaccurate.  (cast drops const qualifier is a warning, not an
error.)


However, this is also an example:

extern void foo();
int main(void)
{
 int j=2;
 foo((double *) j);
 printf(%d\n, j);
 return 0;
}

The compiler has every right to assume that 'j' still has the value '2' in
the 'printf' call because 'j' is local to 'main' and no modification through
a 'double *' pointer can possibly change the value of an 'int'.


A pointer to an address in memory should much more effectively and
efficiently be viewed as a union of all possible types, including void
* (which, by its definition, must be cast to another type before it
can be accessed).

The equivalent of the offending line would be

foo((double *)(void *) j);

since any access through a void pointer CAN change the value.

Thank you for showing me why I should always include
-fno-strict-aliasing in my gcc commandlines.  It's broken, horribly.

-Kyle H
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Ben Laurie
David Schwartz wrote:
 On Tue, Nov 07, 2006, Bernhard Rosenkraenzer wrote:
 
 gcc 4.2 no longer allows function casting - which is used
 rather heavily by
 openssl. (To make things worse, it compiles but inserts abort()
 statements
 resulting in app crashes).
 
 Ugh, I would've thought that flagging a compiliation error would make more
 sense rather that outputting bad code...
 
 It is perfectly reasonable (though certainly not optimal) for a compiler to
 output bad code when the code it's compiling invokes undefined behavior.

Aren't they doing it when the code it's compiling _may_ invoke undefined
behaviour on other platforms? This does not strike me as perfectly
reasonable.

 You can see http://gcc.gnu.org/ml/gcc/2006-07/msg00037.html

 for a discussion on the gcc devel list.

 Is there a fix to make OpenSSL compatible with gcc 4.2/4.3 yet?
 
 No there isn't yet, some technique will be needed to make this
 still work by
 tweaking some of the macros. Does casting a function to (void *)
 first then
 the function cast work?
 
 Not if by work you mean anything more than accidentally happen to work on
 some platforms. There is no reason a 'void (*) (struct bar *);' needs to be
 even remotely like a 'void (*) (char *);'.

Nevertheless, it is exactly like it on many processors.

 OpenSSL should be fixed to cast the parameters, not the functions.

Casting the functions gives you type-safety. Casting the parameters
means you can have any old crap in the parameters and you don't find out
at compile-time.

 Look at this code:
 
 char *  PEM_ASN1_read_bio(char *(*d2i)(),const char *name,BIO *bp,char **x,
 pem_password_cb *cb, void *u);
 
 #define PEM_read_X509(fp,x,cb,u) (X509 *)PEM_ASN1_read( \
 (char *(*)())d2i_X509,PEM_STRING_X509,fp,(char **)x,cb,u)
 
 #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)
 
 This is just wrong. A pointer to d2i_X509 and a pointer to d2i_SSL_SESSION
 are of different types. You cannot cast them into a common type and then
 write a function that can call either of them through such a pointer.
 
 The error is *NOT* from casting function pointers (like you must do to the
 return from 'dlsym'). It's from casting a pointer to a function of one type
 into a function of *another* type and then *calling* it through that
 pointer.

But it gets cast back to the correct type before it is called. These
casts are done the way they are to get type-safety. Removing that option
strikes me as a bad thing.

Cheers,

Ben.

-- 
http://www.apache-ssl.org/ben.html   http://www.links.org/

There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit. - Robert Woodruff
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Dr. Stephen Henson
On Wed, Nov 08, 2006, Ben Laurie wrote:

 
 But it gets cast back to the correct type before it is called. These
 casts are done the way they are to get type-safety. Removing that option
 strikes me as a bad thing.
 

Yes and that happened to be a way that worked on all the compilers OpenSSL
used at the time.

The main purpose of the casting it to provide type safe checking at compile
time and have no runtime overhead. 

If there is an alternative to achieve the same result (inline calls perhaps?)
then we can have that as a compilation option.

Steve.
--
Dr Stephen N. Henson. Email, S/MIME and PGP keys: see homepage
OpenSSL project core developer and freelance consultant.
Funding needed! Details on homepage.
Homepage: http://www.drh-consultancy.demon.co.uk
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Bernhard Rosenkraenzer
On Tuesday, 7. November 2006 15:54, Dr. Stephen Henson wrote:
 On Tue, Nov 07, 2006, Bernhard Rosenkraenzer wrote:
  gcc 4.2 no longer allows function casting - which is used rather heavily
  by openssl. (To make things worse, it compiles but inserts abort()
  statements resulting in app crashes).

 Ugh, I would've thought that flagging a compiliation error would make more
 sense rather that outputting bad code...

Agreed... Unfortunately sometimes gcc developers' decisions make much sense 
from the point of the compiler implementor than from that of someone actually 
using it.

  Is there a fix to make OpenSSL compatible with gcc 4.2/4.3 yet?

 No there isn't yet, some technique will be needed to make this still work
 by tweaking some of the macros. Does casting a function to (void *) first
 then the function cast work?

Yes, but only in a really really ugly way.
I've attached a patch that make it compile (and work), but I can't say I like 
it.
I've tried all sorts of other things (like putting the void* cast directly 
into the defines, or even adding a (char*) cast and running +1-1 type 
arithmetics on it), but gcc's optimizer is too smart and throws it away, and 
errors out just as if it wasn't there), but the attached patch is the only 
quick fix that works.

I hope someone can come up with a better idea...

-- 
Get your own Linux distribution -- http://www.yold.org/
--- openssl-0.9.8d/crypto/asn1/asn1.h.ark	2006-11-08 19:03:36.0 +0100
+++ openssl-0.9.8d/crypto/asn1/asn1.h	2006-11-08 19:32:10.0 +0100
@@ -902,23 +902,26 @@
 
 /* Used to implement other functions */
 void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x);
+static void * __attribute__((unused)) __ASN1_dup=openssl_fcast(ASN1_dup);
 #define ASN1_dup_of(type,i2d,d2i,x) \
-	((type *(*)(I2D_OF(type),D2I_OF(type),type *))openssl_fcast(ASN1_dup))(i2d,d2i,x)
+	((type *(*)(I2D_OF(type),D2I_OF(type),type *))__ASN1_dup)(i2d,d2i,x)
 #define ASN1_dup_of_const(type,i2d,d2i,x) \
-	((type *(*)(I2D_OF_const(type),D2I_OF(type),type *))openssl_fcast(ASN1_dup))(i2d,d2i,x)
+	((type *(*)(I2D_OF_const(type),D2I_OF(type),type *))__ASN1_dup)(i2d,d2i,x)
 
 void *ASN1_item_dup(const ASN1_ITEM *it, void *x);
 
 #ifndef OPENSSL_NO_FP_API
 void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x);
+static void * __attribute__((unused)) __ASN1_d2i_fp=openssl_fcast(ASN1_d2i_fp);
 #define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \
-	((type *(*)(type *(*)(void),D2I_OF(type),FILE *,type **))openssl_fcast(ASN1_d2i_fp))(xnew,d2i,in,x)
+	((type *(*)(type *(*)(void),D2I_OF(type),FILE *,type **))__ASN1_d2i_fp)(xnew,d2i,in,x)
 void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
 int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x);
+static void * __attribute__((unused)) __ASN1_i2d_fp=openssl_fcast(ASN1_i2d_fp);
 #define ASN1_i2d_fp_of(type,i2d,out,x) \
-	((int (*)(I2D_OF(type),FILE *,type *))openssl_fcast(ASN1_i2d_fp))(i2d,out,x)
+	((int (*)(I2D_OF(type),FILE *,type *))__ASN1_i2d_fp)(i2d,out,x)
 #define ASN1_i2d_fp_of_const(type,i2d,out,x) \
-	((int (*)(I2D_OF_const(type),FILE *,type *))openssl_fcast(ASN1_i2d_fp))(i2d,out,x)
+	((int (*)(I2D_OF_const(type),FILE *,type *))__ASN1_i2d_fp)(i2d,out,x)
 int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x);
 int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags);
 #endif
@@ -927,14 +930,16 @@
 
 #ifndef OPENSSL_NO_BIO
 void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x);
+static void * __attribute__((unused)) __ASN1_d2i_bio=openssl_fcast(ASN1_d2i_bio);
 #define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \
-	((type *(*)(type *(*)(void),D2I_OF(type),BIO *,type **))openssl_fcast(ASN1_d2i_bio))(xnew,d2i,in,x)
+	((type *(*)(type *(*)(void),D2I_OF(type),BIO *,type **))__ASN1_d2i_bio)(xnew,d2i,in,x)
 void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x);
 int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, unsigned char *x);
+static void * __attribute__((unused)) __ASN1_i2d_bio=openssl_fcast(ASN1_i2d_bio);
 #define ASN1_i2d_bio_of(type,i2d,out,x) \
-	((int (*)(I2D_OF(type),BIO *,type *))openssl_fcast(ASN1_i2d_bio))(i2d,out,x)
+	((int (*)(I2D_OF(type),BIO *,type *))__ASN1_i2d_bio)(i2d,out,x)
 #define ASN1_i2d_bio_of_const(type,i2d,out,x) \
-	((int (*)(I2D_OF_const(type),BIO *,const type *))openssl_fcast(ASN1_i2d_bio))(i2d,out,x)
+	((int (*)(I2D_OF_const(type),BIO *,const type *))__ASN1_i2d_bio)(i2d,out,x)
 int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x);
 int ASN1_UTCTIME_print(BIO *fp,ASN1_UTCTIME *a);
 int ASN1_GENERALIZEDTIME_print(BIO *fp,ASN1_GENERALIZEDTIME *a);
@@ -977,8 +982,9 @@
 void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it);
 ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d,
 			  ASN1_OCTET_STRING **oct);
+static void * __attribute__((unused)) __ASN1_pack_string=openssl_fcast(ASN1_pack_string);
 #define ASN1_pack_string_of(type,obj,i2d,oct) \
-	((ASN1_STRING *(*)(type 

RE: OpenSSL breaks with gcc 4.2

2006-11-08 Thread David Schwartz

 But it gets cast back to the correct type before it is called. These
 casts are done the way they are to get type-safety. Removing that option
 strikes me as a bad thing.

It does not. Look closely at how these functions work:

char *PEM_ASN1_read_bio(char *(*d2i)(), const char *name, BIO *bp, char **x,
 pem_password_cb *cb, void *u)
{
unsigned char *p=NULL,*data=NULL;
long len;
char *ret=NULL;

if (!PEM_bytes_read_bio(data, len, NULL, name, bp, cb, u))
return NULL;
p = data;
ret=d2i(x,p,len);
if (ret == NULL)
PEMerr(PEM_F_PEM_ASN1_READ_BIO,ERR_R_ASN1_LIB);
OPENSSL_free(data);
return(ret);
}

Please tell me how the compiler knows what type 'x' should be passed 
as. If
you pass a pointer to a function as 'd2i' whose first type is not defined as
a 'char **', you get undefined behavior -- how can the compiler possibly use
the correct type's passing rules when it thinks the function takes a 'char
**' and it actuall takes an 'X509 **'.

OpenSSL does *not* cast the function back to the correct (exact) type
before it calls it. Neither does it cast the function's parameters to the
right type. As a result, the code only works by luck. In the case of
'PEM_read_X509', it works if 'char **' and 'X509 **' happen to have the same
function parameter rules. Nothing requires this to be the case.

There is now way the compiler can know how to properly pass 'x' to 
'd2i'. A
function cannot call another function whose parameter types it does not know
and can vary.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Peter Waltenberg


 
  Please tell me how the compiler knows what
type 'x' should be passed as. If
you pass a pointer to a function as 'd2i' whose first type is not defined
as
a 'char **', you get undefined behavior -- how can the compiler possibly
use
the correct type's passing rules when it thinks the function takes a 'char
**' and it actuall takes an 'X509 **'.

x is still just a pointer to data -
so it's the same length in any case, all pointers to lvalues are the same
length in C. The only issue there is whether it's aligned correctly - that's
the programmers problem.

Mixing something like char *(*d2i)(),
and char ** IS problematic, since those aren't guaranteed to be the same
length but as far as I can remember OpenSSL doesn't do that.

ret=d2i(x,p,len);


d2i is a function (prototype is unknown)

but I've been told x is a pointer,
p is a pointer, len is long. There's nothing indeterminate about the
size of any of those. 

C isn't a strongly typed language -
there's no language requirement for an accurate function prototype or that
the types of the arguments be correct - only that the size of them is correct.


C is not the same language as C++, this
instance should work with a C compiler - whether or not the compiler is
passing the arguments via the stack or in registers.

Peter

Peter Waltenberg







David Schwartz
[EMAIL PROTECTED] 
Sent by: [EMAIL PROTECTED]
09/11/2006 06:47 AM



Please respond to
openssl-dev





To
openssl-dev@openssl.org


cc



Subject
RE: OpenSSL breaks with gcc
4.2









 But it gets cast back to the correct type before it is called. These
 casts are done the way they are to get type-safety. Removing that
option
 strikes me as a bad thing.

It does not. Look closely at how these functions work:

char *PEM_ASN1_read_bio(char *(*d2i)(), const char *name, BIO *bp, char
**x,
   pem_password_cb *cb, void *u)
{
unsigned char *p=NULL,*data="">
long len;
char *ret=NULL;

if (!PEM_bytes_read_bio(data, len,
NULL, name, bp, cb, u))
return NULL;
p = data;
ret=d2i(x,p,len);
if (ret == NULL)
PEMerr(PEM_F_PEM_ASN1_READ_BIO,ERR_R_ASN1_LIB);
OPENSSL_free(data);
return(ret);
}


Please tell me how the compiler knows what type 'x' should be passed as.
If
you pass a pointer to a function as 'd2i' whose first type is not defined
as
a 'char **', you get undefined behavior -- how can the compiler possibly
use
the correct type's passing rules when it thinks the function takes a 'char
**' and it actuall takes an 'X509 **'.


OpenSSL does *not* cast the function back to the correct (exact) type
before it calls it. Neither does it cast the function's parameters to the
right type. As a result, the code only works by luck. In the case of
'PEM_read_X509', it works if 'char **' and 'X509 **' happen to have the
same
function parameter rules. Nothing requires this to be the case.


There is now way the compiler can know how to properly pass 'x' to 'd2i'.
A
function cannot call another function whose parameter types it does not
know
and can vary.


DS


__
OpenSSL Project
http://www.openssl.org
Development Mailing List   
openssl-dev@openssl.org
Automated List Manager   
  [EMAIL PROTECTED]



Re: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Ben Laurie
Dr. Stephen Henson wrote:
 On Wed, Nov 08, 2006, Ben Laurie wrote:
 
 But it gets cast back to the correct type before it is called. These
 casts are done the way they are to get type-safety. Removing that option
 strikes me as a bad thing.

 
 Yes and that happened to be a way that worked on all the compilers OpenSSL
 used at the time.
 
 The main purpose of the casting it to provide type safe checking at compile
 time and have no runtime overhead. 
 
 If there is an alternative to achieve the same result (inline calls perhaps?)
 then we can have that as a compilation option.

Sure, I have no objection to replacing the kludge. So long as we don't
lose compile-time type-safety.

-- 
http://www.apache-ssl.org/ben.html   http://www.links.org/

There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit. - Robert Woodruff
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Dr. Stephen Henson
On Thu, Nov 09, 2006, Peter Waltenberg wrote:

 
  Please tell me how the compiler knows what type 'x' 
 should be passed as. If
 you pass a pointer to a function as 'd2i' whose first type is not defined 
 as
 a 'char **', you get undefined behavior -- how can the compiler possibly 
 use
 the correct type's passing rules when it thinks the function takes a 'char
 **' and it actuall takes an 'X509 **'.
 
 x is still just a pointer to data - so it's the same length in any case, 
 all pointers to lvalues are the same length in C. The only issue there is 
 whether it's aligned correctly - that's the programmers problem.
 
 Mixing something like char *(*d2i)(), and char ** IS problematic, since 
 those aren't guaranteed to be the same length but as far as I can remember 
 OpenSSL doesn't do that.
 
 ret=d2i(x,p,len); 
 
 d2i is a function (prototype is unknown) 
 but I've been told  x is a pointer, p is a pointer, len is long. There's 
 nothing indeterminate about the size of any of those. 
 
 C isn't a strongly typed language - there's no language requirement for an 
 accurate function prototype or that the types of the arguments be correct 
 - only that the size of them is correct. 
 
 C is not the same language as C++, this instance should work with a C 
 compiler - whether or not the compiler is passing the arguments via the 
 stack or in registers.
 

The d2i() case BTW can be replaced in most cases by an equivalent which uses
ASN1_ITEM which doesn't have this problem. There are a few ASN1_ITEM
replacements for some functions but nothing for PEM (yet).

Steve.
--
Dr Stephen N. Henson. Email, S/MIME and PGP keys: see homepage
OpenSSL project core developer and freelance consultant.
Funding needed! Details on homepage.
Homepage: http://www.drh-consultancy.demon.co.uk
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Kurt Roeckx
On Wed, Nov 08, 2006 at 12:47:03PM -0800, David Schwartz wrote:
 
  But it gets cast back to the correct type before it is called. These
  casts are done the way they are to get type-safety. Removing that option
  strikes me as a bad thing.
 
 It does not. Look closely at how these functions work:
 
 char *PEM_ASN1_read_bio(char *(*d2i)(), const char *name, BIO *bp, char **x,
  pem_password_cb *cb, void *u)

That seems to be 0.9.7 code, in 0.9.8 it looks like:
void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x,
pem_password_cb *cb, void *u)

And we have:
typedef void *d2i_of_void(void **,const unsigned char **,long);

The example mentioned in on the gcc list seems to be:
X509 *PEM_read_X509_AUX(FILE *fp, X509 **x, pem_password_cb *cb, void *u)
{ 
return(((X509 *(*)(X509 *(*)(X509 **,const unsigned char **,long),char 
*,FILE *,X509 **,pem_password_cb *,void 
*))((openssl_fptr)PEM_ASN1_read))(d2i_X509_AUX, TRUSTED 
CERTIFICATE,fp,x,cb,u));
}

We have:
void * PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
pem_password_cb *cb, void *u);

What happens here is that PEM_ASN1_read() first gets cast to an
openssl_fptr which is:
typedef void (*openssl_fptr)(void);

And then to an:
X509 *(*)(X509 *(*)(X509 **,const unsigned char **,long),char *,FILE
*,X509 **,pem_password_cb *,void *)

And we have:
X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length);

What I think the problem is, is that you use d2i_of_void *d2i while
you mean d2i_of_void d2i.

d2i_of_void *d2i would be a pointer to a pointer to a function, while
d2i_of_void d2i would be just a pointer to a function.


Kurt

__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-08 Thread David Schwartz

 x is still just a pointer to data - so it's the same
 length in any case, all pointers to lvalues are the
 same length in C. The only issue there is whether it's
 aligned correctly - that's the programmers problem.

Length is not the issue. There is no rule that says that two types must be
passed the same way just because they're the same length. For example, some
platforms may pass a 64-bit floating point number in a floating point
register but pass a 64-bit integer in an integer register.

All you can do is assume that it will work because it has always worked,
until it stops working.

 Mixing something like char *(*d2i)(), and char ** IS
 problematic, since those aren't guaranteed to be the
 same length but as far as I can remember OpenSSL doesn't
 do that.

If they are not the same length, it is not likely to work. That doesn't mean
it's legal if they are the same length.

 ret=d2i(x,p,len);

 d2i is a function (prototype is unknown)
 but I've been told  x is a pointer, p is a pointer,
 len is long. There's nothing indeterminate about the
 size of any of those.

The issue is not size, it's type.

 C isn't a strongly typed language - there's no language
 requirement for an accurate function prototype or that
 the types of the arguments be correct - only that the
 size of them is correct.

You are correct, but that's not the issue. The issue is this simple -- if
you are going to call a function whose types you don't know (through a
prototype), you must cast each type you pass to the type the function
expects. End of story. OpenSSL does not do this. This is not valid C whether
or not the type sizes are the same.

 C is not the same language as C++, this instance should
 work with a C compiler - whether or not the compiler is
 passing the arguments via the stack or in registers.

Can you cite anything in the C standard that says this is allowed? As I
understand it, you must pass a function precisely the types it expects, or
use a prototype to force the compiler to cast them. Either way, the exact
type must be known where the call is compiled.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-08 Thread Richard Levitte - VMS Whacker
In message [EMAIL PROTECTED] on Wed, 8 Nov 2006 21:59:19 -0800, David 
Schwartz [EMAIL PROTECTED] said:

davids You are correct, but that's not the issue. The issue is this
davids simple -- if you are going to call a function whose types you
davids don't know (through a prototype), you must cast each type you
davids pass to the type the function expects. End of story. OpenSSL
davids does not do this. This is not valid C whether or not the type
davids sizes are the same.

So basically, you're saying that KR-style functions (non-prototyped)
aren't handled in a pre-prototype manner any more?  That's a fairly
extreme change of how C used to work.  While I understand such a
change, it's going to break quite a lot of things that still have
non-prototyped functions.

Can you provide something in the C standard that supports this change?

Cheers,
Richard

-
Please consider sponsoring my work on free software.
See http://www.free.lp.se/sponsoring.html for details.

-- 
Richard Levitte [EMAIL PROTECTED]
http://richard.levitte.org/

When I became a man I put away childish things, including
 the fear of childishness and the desire to be very grown up.
-- C.S. Lewis
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


OpenSSL breaks with gcc 4.2

2006-11-07 Thread Bernhard Rosenkraenzer
gcc 4.2 no longer allows function casting - which is used rather heavily by 
openssl. (To make things worse, it compiles but inserts abort() statements 
resulting in app crashes).

You can see http://gcc.gnu.org/ml/gcc/2006-07/msg00037.html

for a discussion on the gcc devel list.

Is there a fix to make OpenSSL compatible with gcc 4.2/4.3 yet?
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


Re: OpenSSL breaks with gcc 4.2

2006-11-07 Thread Dr. Stephen Henson
On Tue, Nov 07, 2006, Bernhard Rosenkraenzer wrote:

 gcc 4.2 no longer allows function casting - which is used rather heavily by 
 openssl. (To make things worse, it compiles but inserts abort() statements 
 resulting in app crashes).
 

Ugh, I would've thought that flagging a compiliation error would make more
sense rather that outputting bad code...

 You can see http://gcc.gnu.org/ml/gcc/2006-07/msg00037.html
 
 for a discussion on the gcc devel list.
 
 Is there a fix to make OpenSSL compatible with gcc 4.2/4.3 yet?

No there isn't yet, some technique will be needed to make this still work by
tweaking some of the macros. Does casting a function to (void *) first then
the function cast work?

Steve.
--
Dr Stephen N. Henson. Email, S/MIME and PGP keys: see homepage
OpenSSL project core developer and freelance consultant.
Funding needed! Details on homepage.
Homepage: http://www.drh-consultancy.demon.co.uk
__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]


RE: OpenSSL breaks with gcc 4.2

2006-11-07 Thread David Schwartz

 On Tue, Nov 07, 2006, Bernhard Rosenkraenzer wrote:

  gcc 4.2 no longer allows function casting - which is used
  rather heavily by
  openssl. (To make things worse, it compiles but inserts abort()
  statements
  resulting in app crashes).

 Ugh, I would've thought that flagging a compiliation error would make more
 sense rather that outputting bad code...

It is perfectly reasonable (though certainly not optimal) for a compiler to
output bad code when the code it's compiling invokes undefined behavior.

  You can see http://gcc.gnu.org/ml/gcc/2006-07/msg00037.html
 
  for a discussion on the gcc devel list.
 
  Is there a fix to make OpenSSL compatible with gcc 4.2/4.3 yet?

 No there isn't yet, some technique will be needed to make this
 still work by
 tweaking some of the macros. Does casting a function to (void *)
 first then
 the function cast work?

Not if by work you mean anything more than accidentally happen to work on
some platforms. There is no reason a 'void (*) (struct bar *);' needs to be
even remotely like a 'void (*) (char *);'. OpenSSL should be fixed to cast
the parameters, not the functions.

Look at this code:

char *  PEM_ASN1_read_bio(char *(*d2i)(),const char *name,BIO *bp,char **x,
pem_password_cb *cb, void *u);

#define PEM_read_X509(fp,x,cb,u) (X509 *)PEM_ASN1_read( \
(char *(*)())d2i_X509,PEM_STRING_X509,fp,(char **)x,cb,u)

#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)

This is just wrong. A pointer to d2i_X509 and a pointer to d2i_SSL_SESSION
are of different types. You cannot cast them into a common type and then
write a function that can call either of them through such a pointer.

The error is *NOT* from casting function pointers (like you must do to the
return from 'dlsym'). It's from casting a pointer to a function of one type
into a function of *another* type and then *calling* it through that
pointer.

DS


__
OpenSSL Project http://www.openssl.org
Development Mailing List   openssl-dev@openssl.org
Automated List Manager   [EMAIL PROTECTED]