Flexible array members is a special type of struct, where the last element of a structure with more than one named member is has an incomplete array type; that is, the size of the array is not specified within the struct.
This technique has widely been known as the "struct hack." However, the classical method of the "struct hack" results in undefined behavior, although it may work most of the time.
Non-Compliant Code Example
The following is the old, incorrect "struct hack" which results in undefined behavior.
struct hack { int num; char my_char; int data[1]; }; ... /* Space is allocated for the struct */ struct hack *hackP = malloc(sizeof(struct hack) + sizeof(int) * (ARRAY_SIZE-1)); if (!hackP) { /* handle malloc failure */ } hackP->num = SOME_NUMBER; hackP->my_char = SOME_CHAR; /* Access data[] as if it had been allocated as data[ARRAY_SIZE] */ for (i = 0; i < ARRAY_SIZE; i++) { hackP->data[i] = i; }
This is, strictly speaking, undefined behavior when accessing hackP->data[i]
for i > 0, because that goes beyond the bounds of the array.
Compliant Solution
The solution is part of the C99 standard, the flexible array member.
struct flexArrayStruct{ int num; char my_char; int data[]; }; ... /* Space is allocated for the struct */ struct flexArrayStruct *structP = malloc(sizeof(struct flexArrayStruct) + sizeof(int) * ARRAY_SIZE); if (!structP) { /* handle malloc failure */ } /* Now, it is as if the struct were defined struct {int num; char my_char; int data[ARRAY_SIZE];} *structP; and we can access the elements as if they were so. */ structP->num = SOME_NUMBER; structP->my_char = SOME_CHAR; /* Access data[] as if array had been allocated as data[ARRAY_SIZE] */ for (i = 0; i < ARRAY_SIZE; i++) { structP->data[i] = i; }
No actual array space is allocated within the struct object. By mallocating space for the struct, the space computation is done at runtime, and allows the programmer to dynamically allocate space for an array within a struct.
However, some restrictions do apply. The incomplete array type MUST be the last element within the struct. You also cannot have an array of objects if the object has flexible array members. Nor can such object be used as a member in the middle of another struct.
Risk Assessment
Although the old "stack hack" method results in undefined behavior, it will work most of the time.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
MEM38-C |
1 (low) |
1 (unlikely) |
3 (low) |
P3 |
L3 |
References
[[McCluskey 01]] ;login:, July 2001, Volume 26, Number 4
[[ISO/IEC 9899-1999]] Section 6.7.2.1, "Structure and union specifiers"