Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The C11 Standard [ISO/IEC 9899:2011] introduced a new term: temporary lifetime. This term still remains in the C23 Standard. Modifying an object with temporary lifetime is undefined behavior. According to subclause 6.2.4, paragraph 8 [ISO/IEC 9899:2024]

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 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, they may return structs or unions that contain arrays. Consequently, 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 's return value contains returns by value a struct or union containing an array, that array should never be modified do not modify those arrays within the expression containing the function call. In C99 and older, it should also never be accessed.

Noncompliant Code Example

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 34 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.

Code Block
bgColor#FFCCCC
langc
#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.

Code Block
bgColor#ccccff
langc
#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.

Code Block
bgColor#ccccff
langc
#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 The following noncompliant code attempts to retrieve an array and increment the array's first value from . The array is part of a struct that is returned by a function call. Since Consequently, the array has temporary lifetime, and modifying the array is being modified, this results in undefined behavior in both C99 and C11.

Code Block
bgColor#FFCCCC
langc
#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().

Code Block
bgColor#ccccff
langc
#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

...

The following This noncompliant code example attempts to save a pointer to retrieve an array from 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.

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>

struct X { charint a[6]; };

struct X addressee(void) {
  struct X result = { "world"{ 1, 2, 3, 4, 5, 6 } };
  return result;
}

int main(void) {
  int *my_a = addressee().a;
  printf("Hello, %s!\n%x", addressee().amy_a[0]);
  return 0;
}

Compliant Solution

This solution is problematic in C99 because of three inherent properties of C:

...

compliant solution stores the structure returned by the call to addressee()

...

Consequently, when printf() tries to dereference the pointer passed as its second argument, it is likely to find garbage.

Note that the behavior of this code in the C Standard is defined, because the lifetime of temporary objects extends to the full expression containing it.

Implementation Details

This code compiles cleanly and runs without error under Microsoft Visual C++ Version 8.0. On the GCC compiler version 4.2, the program compiles with a warning when the -Wall switch is used, and execution on Linux results in a segmentation fault. However, if the flag --std=c99 is passed to the GCC compiler, the program compiles with no warning and runs with no error.

Compliant Solution (C99)

This compliant solution stores the structure returned by the call to addressee() as my_x before calling the printf() function 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().

Code Block
bgColor#ccccff
langc
#include <stdio.h>

struct X { charint a[6]; };

struct X addressee(void) {
  struct X result = { { "world" 1, 2, 3, 4, 5, 6 } };
  return result;
}

int main(void) {
  struct X my_x = addressee();
  int *my_a = my_x.a;
  printf("Hello, %s!\n%x", my_x.a[0]);
  return 0;
}

Risk Assessment

Attempting to access or modify an array within a function after a subsequent sequence point array or access it after its lifetime expires may result in unexpected and perhaps unintended erroneous program behavior.

Rule

Severity

Likelihood

Detectable

Remediation Cost

Repairable

Priority

Level

EXP35-C

Low

low

Probable

probable

Yes

medium

Yes

P4

P6

L3

L2

Automated Detection

Tool

Version

Checker

Description

GCC
Astrée
Include Page
Astrée_V
GCC
Astrée_V
temporary-object-modificationPartially checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite

GCC

_V

 

Can detect violations of this rule when the -Wall flag is used.

Axivion Bauhaus Suite_V

CertC-EXP35
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.CAST.ARRAY.TEMP

Array to Pointer Conversion on Temporary Object
Cppcheck Premium

Include Page
Cppcheck Premium_V
Cppcheck Premium_V

premium-cert-exp35-c
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C0450, C0455, C0459, C0464, C0465

C++3807, C++3808

Fully implemented
LDRA tool suite
Include Page
LDRA_V
LDRA_V
642 S, 42 D, 77 DEnhanced Enforcement
Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_C-EXP35-a

Do not modify objects with temporary lifetime

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT-C: Rule EXP35-CChecks for accesses on objects with temporary lifetime (rule fully covered)
Splint
Include Page
Splint_V
Splint_V



RuleChecker
Include Page
RuleChecker_V
RuleChecker_V

 

temporary-object-modificationPartially checked
 

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

ISO/IEC TR 24772:2013Dangling References to Stack
Frames 
Frames [DCM]Prior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TR 24772:2013Side-effects and Order of Evaluation [SAM
]

...

]Prior to 2018-01-12: CERT: Unspecified Relationship

Bibliography

[ISO/IEC 9899:2024]6.2.4, "Storage Durations of Objects"


...

Image Modified Image Modified Image Modified