Reputation: 9521
Consider the following example:
typedef struct test_flex_arr{
size_t sz;
struct {
int i;
const char *path;
} info[];
} tfa;
int main(void){
size_t sz = 100;
tfa *ptr = malloc(sizeof *ptr + sizeof (*((tfa*) NULL)).info[sz]);
ptr->info[99].i = 10;
printf("%d\n", ptr->info[99].i); //prints 10
}
I expected this program to crash but it runs just fine. As specified 6.5.3.4(p2)
:
The
sizeof
operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant
The type of the operand of sizeof ((*((tfa*) NULL)).info)[sz]
is variable length array so the operand should be evaluated. But evaluation of the operand means derefencing NULL
which I expected to lead to crash.
Is the behavior of the code well defined?
Upvotes: 1
Views: 159
Reputation: 780818
(*((tfa*) NULL)).info[sz]
is not a variable length array type, because (*((tfa*) NULL)).info
is not a type.
So it's treating that as an ordinary expression, referring to the sz
element of the array (*((tfa*) NULL)).info
. Per the quoted specification, this is not evaluated, so the fact that it dereferences NULL
doesn't cause undefined behavior. It simply returns the size of the array element, which is not dependent on the location of the array or the index. That's why it compiles without warning and doesn't crash.
But this doesn't produce the desired result. You're only getting the size of one element of the array, not the sz
elements that you actually need to allocate space for. You need to multiply the size of an element by the number of elements. So use
tfa *ptr = malloc(sizeof *ptr + sz * sizeof ptr->info[0]);
Upvotes: 8