Aliasing bug when casting char[] into char* ?

X

Xavier Roche

Hi folks,

I have a probably rather silly question: is casting a char array in a
char* a potential source of aliasing bug ?

Example: a fonction returning a buffer taken in a circular buffer

typedef struct foo_t foo_t;
struct foo_t {
int index;
char buff[16][8192];
};

static char* getBuff(foo_t *s) {
s->index = ( s->index + 1 ) % 16;
printf("returning s->buff[%d] == %p\n",
s->index, s->buff[s->index]);
return s->buff[s->index];
}

void test(char *a, char *b) {
printf("got pointers: %p %p\n", a, b);
}

int main(void) {
foo_t s = { 0 };
test(getBuff(&s), getBuff(&s));
return 0;
}

The problem is that on Visual C++ 2003, the two returned pointers are
identical when optimizing (!)

Tested with Visual C++ 2003, release mode (optimized)

returning s->buff[1] == 00111F5C
returning s->buff[2] == 00113F5C
got pointers: 00113F5C 00113F5C

Tested with gcc 3.3.4, optimized (O4):

returning s->buff[1] == 0xfffde008
returning s->buff[2] == 0xfffe0008
got pointers: 0xfffde008 0xfffe0008

Is the bug inside this code ? (or inside the compiler ?)
 
M

matevzb

Hi folks,

I have a probably rather silly question: is casting a char array in a
char* a potential source of aliasing bug ?
I'm not sure what you mean, I don't see any casts in your code.
Example: a fonction returning a buffer taken in a circular buffer
#include said:
typedef struct foo_t foo_t;
struct foo_t {
int index;
char buff[16][8192];
};

static char* getBuff(foo_t *s) {
s->index = ( s->index + 1 ) % 16;
printf("returning s->buff[%d] == %p\n",
s->index, s->buff[s->index]);
When using %p, the argument must be a pointer to void, so you need an
explicit cast here:
(void *)s->buff[s->index]
return s->buff[s->index];
}

void test(char *a, char *b) {
printf("got pointers: %p %p\n", a, b);
Same as above, a missing (void *) cast.
}

int main(void) {
foo_t s = { 0 };
test(getBuff(&s), getBuff(&s));
The order of evaluation is unspecified for function arguments, so
don't use it like this. Better:
char *p1 = getBuff (&s);
char *p2 = getBuff (&s);
test (p1, p2);
return 0;
}

The problem is that on Visual C++ 2003, the two returned pointers are
identical when optimizing (!)
I'm probably missing something here, but someone else will point out
the (obvious) problem. I suggest you fix the above problems first and
see if it helps.
<snip>
 
E

Eric Sosman

Xavier Roche wrote On 02/06/07 16:17,:
Hi folks,

I have a probably rather silly question: is casting a char array in a
char* a potential source of aliasing bug ?

Example: a fonction returning a buffer taken in a circular buffer

typedef struct foo_t foo_t;
struct foo_t {
int index;
char buff[16][8192];
};

static char* getBuff(foo_t *s) {
s->index = ( s->index + 1 ) % 16;
printf("returning s->buff[%d] == %p\n",
s->index, s->buff[s->index]);
return s->buff[s->index];
}

void test(char *a, char *b) {
printf("got pointers: %p %p\n", a, b);
}

int main(void) {
foo_t s = { 0 };
test(getBuff(&s), getBuff(&s));
return 0;
}

The problem is that on Visual C++ 2003, the two returned pointers are
identical when optimizing (!)

Tested with Visual C++ 2003, release mode (optimized)

returning s->buff[1] == 00111F5C
returning s->buff[2] == 00113F5C
got pointers: 00113F5C 00113F5C

Tested with gcc 3.3.4, optimized (O4):

returning s->buff[1] == 0xfffde008
returning s->buff[2] == 0xfffe0008
got pointers: 0xfffde008 0xfffe0008

Is the bug inside this code ? (or inside the compiler ?)

It looks like the compiler is at fault (or else I've
missed something). The two pointers could appear in either
order in the "got pointers" line because the compiler can
choose to evaluate the `a' argument either before or after
the `b' argument, but no matter which order it chooses the
two printed values should be different.
 
O

Old Wolf

static char* getBuff(foo_t *s) {
s->index = ( s->index + 1 ) % 16;
printf("returning s->buff[%d] == %p\n",
s->index, s->buff[s->index]);
return s->buff[s->index];
}

void test(char *a, char *b) {
printf("got pointers: %p %p\n", a, b);
}

int main(void) {
foo_t s = { 0 };
test(getBuff(&s), getBuff(&s));
return 0;
}

Tested with Visual C++ 2003, release mode (optimized)

returning s->buff[1] == 00111F5C
returning s->buff[2] == 00113F5C
got pointers: 00113F5C 00113F5C

Has to be a compiler bug. I wonder if you could inspect the
assembly code generated, and see what it is actually
doing. Does it make any difference if you remove the
'static' keyword? (Not that it should, but perhaps the
compiler is getting confused).

Also, check that the compiler is in ISO C++ compliance
mode (if it has one!); some compilers have optimization
switches that violate the standard (ie. make assumptions
that are not guaranteed).
 
P

Peter Nilsson

Xavier Roche said:
Hi folks,

I have a probably rather silly question: is casting a char array in a
char* a potential source of aliasing bug ?

Example: a fonction returning a buffer taken in a circular buffer

I don't see a #include <stdio.h> header anywhere.

If that's missing then you don't have a prototype for the variadic
function
printf. Which means the behaviour is undefined.
typedef struct foo_t foo_t;
struct foo_t {
int index;
char buff[16][8192];

This means the struct is at least 131072 bytes. This exceeds the
minimum
required implementation limit of 32767 bytes of an object in C90.

What happens if you make the buffers smaller...?

char buff[16][16];

I suggest you allocate the buffers dynamically.
};

static char* getBuff(foo_t *s) {
s->index = ( s->index + 1 ) % 16;
printf("returning s->buff[%d] == %p\n",
s->index, s->buff[s->index]);

Although char * and void * are required to have the same
representation,
you're best of converting the second parameter to void * as required
by
%p.
return s->buff[s->index];

}

void test(char *a, char *b) {
printf("got pointers: %p %p\n", a, b);
Ditto.


}

int main(void) {
foo_t s = { 0 };
test(getBuff(&s), getBuff(&s));
return 0;
}

The problem is that on Visual C++ 2003, the two returned pointers are
identical when optimizing (!)

Tested with Visual C++ 2003, release mode (optimized)

returning s->buff[1] == 00111F5C
returning s->buff[2] == 00113F5C
got pointers: 00113F5C 00113F5C

Tested with gcc 3.3.4, optimized (O4):

returning s->buff[1] == 0xfffde008
returning s->buff[2] == 0xfffe0008
got pointers: 0xfffde008 0xfffe0008
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top