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