Section 6.5.2.5 of the ISO/IEC 9899:1999 (C99) standard defines a compound literal as:
A postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers ... The value of a compound literal is that of an unnamed object initiated by the initializer list
The storage for this object is either static if the compound literal occurs at file scope or automatic if the compound literal occurs at block scope (6.5.2.5.6).
For example, in the following function:
void func(void) { int *ip = (int[4]){1,2,3,4}; /* ... */ }
following initialization, the int
pointer ip
contains the address of an unnamed object of type int [4]
, allocated on the stack.
Note that only one object is created per compound literal -- even if the compound literal appears in a loop and has dynamic initializers (6.5.2.5.16).
Noncompliant Code Example
In this noncompliant code example, the programmer mistakenly assumes that the elements of the ints
array of pointer to int_struct
are assigned the addresses of distinct int_struct
objects, one for each integer in the range [0, MAX_INTS-1]:
#include <stdio.h> typedef struct int_struct { int x; } int_struct; #define MAX_INTS 10 int main(void){ size_t i; int_struct *ints[MAX_INTS]; for (i = 0; i < MAX_INTS; i++) { ints[i] = &(int_struct){i}; } for (i = 0; i < MAX_INTS; i++) { printf("%d\n", ints[i]->x); } }
However, only one int_struct
object is created. At each iteration of the first loop, the x
member of this object is set equal to the current value of the loop counter i
. Therefore, after the first loop terminates, the value of the x
member is MAX_INTS - 1
.
During the print loop, this value is printed MAX_INTS times because every pointer in the "ints" array is set to point to the (single) int_struct
object.
This is contrary to the intuitive expected result, which is that the integers 0 through MAX_INTS-1 would be printed in order.
Compliant Solution
This compliant solution uses an array of structures rather than an array of pointers. That way, an actual copy of each int_struct
(rather than a pointer to the object) is stored.
#include <stdio.h> typedef struct int_struct { int x; } int_struct; #define MAX_INTS 10 int main(void){ int i; int_struct ints[MAX_INTS]; for(i=0;i<MAX_INTS;i++) ints[i] = (int_struct){i}; for(i=0;i<MAX_INTS;i++) printf("%d\n",ints[i].x); }
Risk Assessment
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
DCL21-C |
low |
unlikely |
medium |
P2 |
L3 |
References
[ISO/IEC 9899:1999] Section 6.5.2.5 (Compound Literals)