CertC-DCL21ΒΆ
Understand the storage of compound literals
Required inputs: IR
Subclause 6.5.2.5 of the C Standard [ ISO/IEC 9899:2011] 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 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. For example, in the 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. Once
func returns, any attempts to access this object will produce
undefined
behavior.
Note that only one object is created per compound literal-even if the compound literal appears in a loop and has dynamic initializers.
This recommendation is a specific instance of 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]:
#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 9 (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.
#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 |
Bibliography
| [ ISO/IEC 9899:2011] | Subclause 6.5.2.5, "Compound Literals" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
escaping_compound_literal_address |
The address of a compound literal should not escape its block |
None |
False |
Options
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
This rule has no individual options.