Section Subclause 6.5.2.5 of the of the C Standard [ISO/IEC 9899:1999 (C99) standard defines a compound literal as \[[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\]2011] defines a compound literal as Wiki Markup
A postfix A postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers. . . . The value of a of the 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), and the storage duration is associated with its immediate enclosing block (\[[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\], Section 6.5.2. 5.6). For example, in the function Wiki Markup
Code Block |
---|
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. Once {{func
}} returns, any attempts to access this object will produce undefined behavior.unmigrated-wiki-markup
Note that only one object is created per compound literal \-\- even if the compound literal appears in a loop and has dynamic initializers (\[[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\], Section 6.5.2.5.16).compound literal—even if the compound literal appears in a loop and has dynamic initializers.
This recommendation is a specific instance of rule DCL30-C. Declare objects with appropriate storage durations.
Noncompliant Code Example
...
In this noncompliant code example, the programmer mistakenly assumes that the elements of the {{ints
}} array of the pointer to {{int_struct
}} are assigned the addresses of distinct {{int_struct
}} objects, one for each integer in the range \[0,
MAX_INTS - 1
\]
:
Code Block | ||||
---|---|---|---|---|
| ||||
#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); } return 0; } |
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, just before the first loop terminates, the value of the x
member is MAX_INTS - 1
.
Because the storage duration of the compound literal is associated with the for
loop that contains it, dereferencing ints
in the second loop results in undefined behavior 8: an object is referred to outside of its lifetime9 (Annex J of the C Standard).
Even if the region of memory that contained the compound literal is not written to between loops, the print loop will display the value MAX_INTS - 1
for MAX_INTS
lines. 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.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
#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); } return 0; } |
Risk Assessment
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DCL21-C |
Low |
Unlikely |
Medium | P2 | L3 |
Related Guidelines
Automated Detection
Tool | Version | Checker | Description | ||||||
Axivion Bauhaus Suite |
| CertC-DCL21 | |||||||
Helix QAC |
| C1054, C3217 |
Bibliography
...
2011] | Subclause 6.5.2.5 |
...
, "Compound Literals |
...
" |
...
Bibliography
DCL20-C. Always specify void even if a function accepts no arguments 02. Declarations and Initialization (DCL)