I _think_ I understand C strict aliasing - it's based on the type of
expressions.  In the testcase below, the type of expressions is the same, which
is why I think it's a compiler bug.

The bug is reproducible with gcc 4.1.0 on multiple platforms.  I've tried i386
(i686) and alpha myself and am able to reproduce the problem on both.  The
original reporter of the problem with my program (the real one, not the
testcase) was able to reproduce the problem on other architectures.

The problem does not occur with gcc 2.95.3 and 3.4.5.

Basically, in the program below, gcc 4.1.0 would pre-load BF_current.P[0] and
BF_current.P[17] into registers or stack locations - however the loop modifies
P[0] via ptr.

#include <stdio.h>
#include <string.h>

#define BF_N 16

typedef unsigned int BF_word;
typedef BF_word BF_key[BF_N + 2];

static struct {
        BF_word S[4][0x100];
        BF_key P;
} BF_current;

#define BF_ROUND(L, R, N) \
        tmp1 = L & 0xFF; \
        tmp2 = L >> 8; \
        tmp2 &= 0xFF; \
        tmp3 = L >> 16; \
        tmp3 &= 0xFF; \
        tmp4 = L >> 24; \
        tmp1 = BF_current.S[3][tmp1]; \
        tmp2 = BF_current.S[2][tmp2]; \
        tmp3 = BF_current.S[1][tmp3]; \
        tmp3 += BF_current.S[0][tmp4]; \
        tmp3 ^= tmp2; \
        R ^= BF_current.P[N + 1]; \
        tmp3 += tmp1; \
        R ^= tmp3;

#define BF_ENCRYPT \
        L ^= BF_current.P[0]; \
        { \
                int i; \
                for (i = 0; i < BF_N; i += 2) { \
                        BF_ROUND(L, R, i); \
                        BF_ROUND(R, L, i+1); \
                } \
        } \
        tmp4 = R; \
        R = L; \
        L = tmp4 ^ BF_current.P[BF_N + 1];

int main(void)
{
        BF_word L, R;
        BF_word tmp1, tmp2, tmp3, tmp4, *ptr;
        BF_word i, j;

        for (i = 0; i < 4; i++)
                for (j = 0; j < 0x100; j++)
                        BF_current.S[i][j] = (i + 0x12345678) * j;
        for (i = 0; i < BF_N + 2; i++)
                BF_current.P[i] = i * 0x98765432;

        L = R = 0;
        ptr = BF_current.P;
        do {
#ifndef WORKAROUND
                ptr += 2;
                BF_ENCRYPT;
                *(ptr - 2) = L;
                *(ptr - 1) = R;
#else
                BF_ENCRYPT;
                *ptr = L;
                *(ptr + 1) = R;
                ptr += 2;
#endif
        } while (ptr < &BF_current.P[BF_N + 2]);

        printf("%08x %08x\n", L, R);

        return 0;
}

host!user:~$ gcc gcc-4.1.0-aliasing-bug.c -o gcc-4.1.0-aliasing-bug -Wall -O2
-fno-strict-aliasing
host!user:~$ ./gcc-4.1.0-aliasing-bug 
8261e2e6 f1f1bc33
host!user:~$ gcc gcc-4.1.0-aliasing-bug.c -o gcc-4.1.0-aliasing-bug -Wall -O2 
host!user:~$ ./gcc-4.1.0-aliasing-bug 
46be060b df072f90
host!user:~$ gcc gcc-4.1.0-aliasing-bug.c -o gcc-4.1.0-aliasing-bug -Wall -O2
-DWORKAROUND
host!user:~$ ./gcc-4.1.0-aliasing-bug 
8261e2e6 f1f1bc33
host!user:~$ uname -mrs
Linux 2.4.32-ow1 alpha
host!user:~$ gcc -v
Using built-in specs.
Target: alphaev56-unknown-linux-gnu
Configured with: ./configure --prefix=/home/user/gcc-4.1.0
Thread model: posix
gcc version 4.1.0

(i386 gives the same results)


-- 
           Summary: strict aliasing incorrectly pre-loads an array element
           Product: gcc
           Version: 4.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: solar at openwall dot com
 GCC build triplet: i686-pc-linux-gnu
  GCC host triplet: i686-pc-linux-gnu
GCC target triplet: i686-pc-linux-gnu


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26587

Reply via email to