This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c/69776] Wrong optimization with aliasing
- From: "ch3root at openwall dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Thu, 11 Feb 2016 23:49:15 +0000
- Subject: [Bug c/69776] Wrong optimization with aliasing
- Auto-submitted: auto-generated
- References: <bug-69776-4 at http dot gcc dot gnu dot org/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69776
--- Comment #2 from Alexander Cherepanov <ch3root at openwall dot com> ---
[CC'ing Martin Sebor and Joseph S. Myers as it's potentially related to
bug 65892.]
On 2016-02-12 01:20, pinskia at gcc dot gnu.org wrote:
>> The last value is wrong, it should be 1.
>
> Why do you think that?
>
> If we look at your code:
>
> void *p = malloc(10);
> int *pi = p;
> double *pd = p;
>
> << at this point p has no effective type.
Ok
> *pi = 1;
> printf("*pi = %d\n", *pi);
>
> << Now it has an effective type of int or a struct containing int
Structs are a separate topic (and I thinks it's still unsettled in the
standard). Fortunately they are not relevant here. Back to int...
C11, 6.5p6: "If a value is stored into an object having no declared type
through an lvalue having a type that is not a character type, then the
type of the lvalue becomes the effective type of the object for that
access and for subsequent accesses that do not modify
the stored value."
So, yes, it has an effective type of int for this store and for
subsequent reads. But not for writes.
> int a = *pi;
>
> << a read
Yes, a read with an effective type of int.
> *pd = 0;
>
> << a write to a double, it does not alias int at all so it can be moved past
> the next statement
This is a write. Hence the previous effective type is not relevant. And
effective type for this write and for subsequent reads is double.
> *pi = a;
>
> << store via an int
>
> Since the order of pi and pd is not specified due to different aliasing of int
> and double so either can be done first
Sorry, I don't see what the talk about moving stores could be based on.
This is another write. So it ignores the previous effective type and
sets a new one.
Looking at it at a higher level: I think it is generally agreed that
allocated memory could be repurposed at will -- once you don't need old
data you just overwrite it with new data without any regard to the
types. I have seen proposals[1] for forbidding this technique but I
don't think it was seriously considered. Maybe I missed it.
[1] https://gcc.gnu.org/ml/gcc/2004-12/msg00193.html
The program in this bug report is loosely based on the Example 1 in DR
236 and I was surprised that the problematic behavior is present even
without functions involved. The variant with a function (closer to the
Example 1 in DR 236):
// file 1
void f(int *qi, double *qd)
{
int i = *qi;
*qd = 0;
*qi = i;
}
// file 2
#include <stdlib.h>
#include <stdio.h>
void f(int *qi, double *qd);
int main()
{
void *p = malloc(10);
int *pi = p;
double *pd = p;
*pi = 1;
printf("*pi = %d\n", *pi);
f(pi, pd);
printf("*pi = %d\n", *pi);
}
I don't know if it should be considered the same case or a separate one.
Most discussions about DR 236 (like in bug 65892) are concerned about
unions and it's not clear to me if the case of allocated objects is
settled or not, in gcc or in general. IMHO the case of allocated objects
is easier (no tricky visibility rules) and more general but maybe I'm
missing something.