M
Maxim Fomin
Problem: there is need to allocate space for some object of unknown quantity and I know, that in "99% cases" it would be less than N items. In such cases it is better to use fixed-size array, however I don't want to impose limitations and cover all possible cases (when quantity is bigger that N). Asa trade-off I use union of fixed-size array with single element:
union u
{
type *arr[N]; /* type is opaque structure */
type *ptr;
};
If quantity is bigger than N, I assign allocated memory to ptr.
However, consider following example program (uhack.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data
{
int val;
char *align;
} d0 = {0, "hello"},
d1 = {1, "world"},
d2 = {2, "from"},
d3 = {3, "a"},
d4 = {4, "simple"},
d5 = {5, "c"},
d6 = {6, "program"};
union
{
struct data *arr[7];
struct data *ptr;
} u = {{&d0, &d1, &d2, &d3, &d4, &d5, &d6}};
int main(void)
{
int i;
struct data *new_ptr;
for (i = 0; i < 7; i++) {
printf("%s\n", u.ptr.align);
}
new_ptr = malloc(9 * sizeof *new_ptr);
memcpy(new_ptr, u.ptr, 7 * sizeof *new_ptr);
u.ptr = new_ptr;
for (i = 0; i < 7; i++) {
printf("%s\n", u.ptr.align);
}
return 0;
}
Compiling with gcc (gcc -Wall -Wextra -pedantic -std=c99 -O0 -o gccO0 -Wstrict-aliasing -fstrict-aliasing uhack.c) gives expected result, but raising optimization level (gcc -Wall -Wextra -pedantic -std=c99 -O1 -o gccO1 -Wstrict-aliasing -fstrict-aliasing uhack.c) gives binary which segfaults onmy machine.
I don't understand where "strict aliasing rules" are broken (assuming that raising optimization level for given program reveals such errors):
- union trick unlikely is a source of problem, since it overlaps compatibletypes (even same): an object and first element of fixed-size array of suchobjects
- union u is likely to be initialized right;
- padding and trailing bits are also unlikely to cause problem, since members are accessed through . and ->
In addition, clang (clang -Wall -Wextra -pedantic -std=c99 -O3 -o clangO3-Wstrict-aliasing -fstrict-aliasing uhack.c) for O3 produces runnable binary, so I suppose there is somewhere tricky UB which I cannot find.
union u
{
type *arr[N]; /* type is opaque structure */
type *ptr;
};
If quantity is bigger than N, I assign allocated memory to ptr.
However, consider following example program (uhack.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data
{
int val;
char *align;
} d0 = {0, "hello"},
d1 = {1, "world"},
d2 = {2, "from"},
d3 = {3, "a"},
d4 = {4, "simple"},
d5 = {5, "c"},
d6 = {6, "program"};
union
{
struct data *arr[7];
struct data *ptr;
} u = {{&d0, &d1, &d2, &d3, &d4, &d5, &d6}};
int main(void)
{
int i;
struct data *new_ptr;
for (i = 0; i < 7; i++) {
printf("%s\n", u.ptr.align);
}
new_ptr = malloc(9 * sizeof *new_ptr);
memcpy(new_ptr, u.ptr, 7 * sizeof *new_ptr);
u.ptr = new_ptr;
for (i = 0; i < 7; i++) {
printf("%s\n", u.ptr.align);
}
return 0;
}
Compiling with gcc (gcc -Wall -Wextra -pedantic -std=c99 -O0 -o gccO0 -Wstrict-aliasing -fstrict-aliasing uhack.c) gives expected result, but raising optimization level (gcc -Wall -Wextra -pedantic -std=c99 -O1 -o gccO1 -Wstrict-aliasing -fstrict-aliasing uhack.c) gives binary which segfaults onmy machine.
I don't understand where "strict aliasing rules" are broken (assuming that raising optimization level for given program reveals such errors):
- union trick unlikely is a source of problem, since it overlaps compatibletypes (even same): an object and first element of fixed-size array of suchobjects
- union u is likely to be initialized right;
- padding and trailing bits are also unlikely to cause problem, since members are accessed through . and ->
In addition, clang (clang -Wall -Wextra -pedantic -std=c99 -O3 -o clangO3-Wstrict-aliasing -fstrict-aliasing uhack.c) for O3 produces runnable binary, so I suppose there is somewhere tricky UB which I cannot find.