This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH]: Fix PR tree-optimization/21407
Geoff Keating wrote:
On 11/05/2005, at 11:39 AM, Mark Mitchell wrote:
If you asked someone twenty years ago whether these kinds of
operations were legal, the answer would have been uniformly yes.
Now, opinions differ, because people are seeing more benefits of
restricting these operations. But, the standards still don't say.
struct I {
virtual void f(); // I is not a POD.
int a;
int b;
};
void g() {
I i;
int *a_p = &i.b;
/* 8 is a magic number! */
I* i_p = (I*)((char *) a_p - 8);
i_p->a = 3;
}
There's no casting between pointers and integers. There are
reinterpet_casts between pointers. The mapping is implementation-
defined, but, in practice, all implementations on, say, IA32, are
going to leave the bit-pattern unchanged. I just don't see anything
that says conclusively that this code is invalid.
In C++, this code clearly invokes unspecified behaviour, initially with
the cast of a_p to 'char *'.
Many people would say, reasonably enough, that specifying the behavior
is specifying (a) the type of the result, and (b) the value. After all,
that's how the descriptions of expressions are written. So, as long as
we specify that the result of the conversion is that you get a "char *"
with the same bit-pattern as "a_p", then there's nothing more for us to
say.
The question is what you can do with a pointer of that type and value.
You can have Nick's alternative #1, and say that you can form pointer
values by any means, and if they happen to point at something of the
type you're dereferencing, then you're OK.
You can have Nick's alternative #3, and give dynamic history to
pointers. That's what the optimizer folks would like; since a_p points
to object with sizeof(int) bytes, you can never derive from it a pointer
pointing outside that region.
But, certainly, nothing in the current standard suggests that what you
can do with a pointer whose value compares equal to that of i.a depends
on whether you got that pointer by writing "&i.a", or by pointer
arithmetic, or by "(int *)0x<right address here>".
(However, if you've never taken the address of any part of "i", then
there's no way for a conforming program to know what address i.a has, so
we can just assume that they didn't get the right value if they try to
just guess a number. And, therefore, we can avoid actually allocating
memory. But, if you've taken the address of some part of "i", then the
program can know the address of i.a.)
Consider:
struct S {
virtual void f();
int a;
int b;
};
void f(int *a_p) {
if (*a_p != 3) abort();
}
void g() {
S s;
s.a = 3;
f((int*) ((char *)&s.b - ((char*) &s.b - (char*) &s.a))));
}
The only thing that can possibly make this code abort is that we're not
allowed to manipulate the pointer to s.b like this. That's going to be
rather surprising, given that we can do an algebraic simplication and
just get:
f ((int *) (char*) &s.a);
which nobody is proposing should result in an abort.
The code is indeed invalid under Nick's model #3, but I sure don't see
anything in the C++ standard to suggest that anybody expected this code
to fail.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
(916) 791-8304