CertC-EXP35ΒΆ
Do not modify objects with temporary lifetime
Required inputs: IR
The C11 Standard [ ISO/IEC 9899:2011] introduced a new term: temporary lifetime. Modifying an object with temporary lifetime is undefined behavior. According to subclause 6.2.4, paragraph 8
A non-lvalue expression with structure or union type, where the structure or union contains a member with array type (including, recursively, members of all contained structures and unions) refers to an object with automatic storage duration and temporary lifetime. Its lifetime begins when the expression is evaluated and its initial value is the value of the expression. Its lifetime ends when the evaluation of the containing full expression or full declarator ends. Any attempt to modify an object with temporary lifetime results in undefined behavior.
This definition differs from the C99 Standard (which defines modifying the result of a function call or accessing it after the next sequence point as undefined behavior) because a temporary object's lifetime ends when the evaluation containing the full expression or full declarator ends, so the result of a function call can be accessed. This extension to the lifetime of a temporary also removes a quiet change to C90 and improves compatibility with C++.
C functions may not return arrays; however,
functions can return a pointer to an array or a
struct or
union that contains arrays. Consequently, in any
version of C, if a function call returns by value a
struct or
union containing an array, do not modify those arrays within the
expression containing the function call. In
C99 and older, do not access an array returned by a function after the next
sequence point or after the evaluation of the containing full expression or
full declarator ends.
Noncompliant Code Example
This noncompliant code example
conforms
to the C11 Standard; however, it fails to conform to C99. If compiled with a
C99-conforming implementation, this code has
undefined
behavior because the sequence point preceding the call to
printf() comes between the call and the access by
printf() of the string in the returned object.
#include <stdio.h>
struct X { char a[8]; };
struct X salutation(void) {
struct X result = { "Hello" };
return result;
}
struct X addressee(void) {
struct X result = { "world" };
return result;
}
int main(void) {
printf("%s, %s!\n", salutation().a, addressee().a);
return 0;
}
Compliant Solution (C11 and newer)
This compliant solution checks
__STDC_VERSION__ to ensure that a pre-C11 compiler will fail to
compile the code, rather than invoking undefined behavior.
#include <stdio.h>
#if __STDC_VERSION__ < 201112L
#error This code requires a compiler supporting the C11 standard or newer
#endif
struct X { char a[8]; };
struct X salutation(void) {
struct X result = { "Hello" };
return result;
}
struct X addressee(void) {
struct X result = { "world" };
return result;
}
int main(void) {
printf("%s, %s!\n", salutation().a, addressee().a);
return 0;
}
Compliant Solution
This compliant solution stores the structures returned by the call to
addressee() before calling the
printf() function. Consequently, this program conforms to both C99
and C11.
#include <stdio.h>
struct X { char a[8]; };
struct X salutation(void) {
struct X result = { "Hello" };
return result;
}
struct X addressee(void) {
struct X result = { "world" };
return result;
}
int main(void) {
struct X my_salutation = salutation();
struct X my_addressee = addressee();
printf("%s, %s!\n", my_salutation.a, my_addressee.a);
return 0;
}
Noncompliant Code Example
This noncompliant code example attempts to retrieve an array and increment the
array's first value. The array is part of a
struct that is returned by a function call. Consequently, the
array has temporary lifetime, and modifying the array is
undefined
behavior in both C99 and C11.
#include <stdio.h>
struct X { int a[6]; };
struct X addressee(void) {
struct X result = { { 1, 2, 3, 4, 5, 6 } };
return result;
}
int main(void) {
printf("%x", ++(addressee().a[0]));
return 0;
}
Compliant Solution
This compliant solution stores the structure returned by the call to
addressee() as
my_x before calling the
printf() function. When the array is modified, its lifetime is no
longer temporary but matches the lifetime of the block in
main().
#include <stdio.h>
struct X { int a[6]; };
struct X addressee(void) {
struct X result = { { 1, 2, 3, 4, 5, 6 } };
return result;
}
int main(void) {
struct X my_x = addressee();
printf("%x", ++(my_x.a[0]));
return 0;
}
Noncompliant Code Example
This noncompliant code example attempts to save a pointer to an array that is
part of a
struct that is returned by a function call. Consequently, the
array has temporary lifetime, and using the pointer to it outside of the full
expression is
undefined
behavior in both C99 and C11.
#include <stdio.h>
struct X { int a[6]; };
struct X addressee(void) {
struct X result = { { 1, 2, 3, 4, 5, 6 } };
return result;
}
int main(void) {
int *my_a = addressee().a;
printf("%x", my_a[0]);
return 0;
}
Compliant Solution
This compliant solution stores the structure returned by the call to
addressee() as
my_x before saving a pointer to its array member. When the pointer
is used, its lifetime is no longer temporary but matches the lifetime of the
block in
main().
#include <stdio.h>
struct X { int a[6]; };
struct X addressee(void) {
struct X result = { { 1, 2, 3, 4, 5, 6 } };
return result;
}
int main(void) {
struct X my_x = addressee();
int *my_a = my_x.a;
printf("%x", my_a[0]);
return 0;
}
Risk Assessment
Attempting to modify an array or access it after its lifetime expires may result in erroneous program behavior.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| EXP35-C | Low | Probable | Medium | P4 | L3 |
Related Guidelines
| Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| ISO/IEC TR 24772:2013 | Dangling References to Stack Frames [DCM] | Prior to 2018-01-12: CERT: Unspecified Relationship |
| ISO/IEC TR 24772:2013 | Side-effects and Order of Evaluation [SAM] | Prior to 2018-01-12: CERT: Unspecified Relationship |
Bibliography
| [ ISO/IEC 9899:2011] | 6.2.4, "Storage Durations of Objects" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
temp_array_decay |
Temporary array converted to pointer |
None |
False |
temp_mutation |
Mutation of temporary array |
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.