> 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 K&R 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]

Reply via email to