Versions Compared

Key

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

Some expressions involve operands that are unevaluated. According to the The C++ Standard, [expr], paragraph 8 [ISO/IEC 14882-2014] states the following:

In some contexts, unevaluated operands appear. An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression. [Note: In an unevaluated operand, a non-static class member may be named (5.1) and naming of objects or functions does not, by itself, require that a definition be provided. — end note]

The following expressions do not evaluate their operands: sizeof()typeid()noexcept()decltype(), and declval().

Because an unevaluated operand in an expression is not evaluated, no side effects from that operand will be are triggered. Reliance on those side effects will result in unexpected behavior. Do not rely on side effects in unevaluated operands.

Note that unevaluated Unevaluated expression operands are used in situations were when the declaration of an object is required , but the definition of the object is not. For instance, in the following example below, the function f() is overloaded, which relies relying on the unevaluated expression operand to select the desired overload, which is then used to determine the result of the sizeof() expression:.

Code Block
languagecpp
int f(int);
double f(double);
 
size_t size = sizeof(f(0));

Such a use

...

does not

...

rely on the side effects of f()

...

and

...

consequently conforms to this guideline.

Noncompliant Code Example (sizeof)

In this noncompliant code example, the expression a++ is not evaluated:.

Code Block
lang
bgColor#FFcccc#FFCCCC
languagelangcppc
#include <iostream>
void f() {
  int a = 14;
  int b = sizeof(a++);
  std::cout << a << ", " << b << std::endl;
}

Consequently, the value of a after b has been initialized is 14.

Compliant Solution (sizeof)

In this compliant solution, the variable a is incremented outside of the sizeof operator:.

Code Block
bgColor#ccccff
languagelangcpplangc
#include <iostream>
void f() {
  int a = 14;
  int b = sizeof(a);
  ++a;
  std::cout << a << ", " << b << std::endl;
}

Noncompliant Code Example (decltype)

In this noncompliant code example, the expression i++ is not evaluated within the decltype specifier:.

Code Block
bgColor#FFcccc#FFCCCC
languagelangcpplangc
#include <iostream>

void f() {
  int i = 0;
  decltype(i++) h = 12;
  std::cout << i;
}

Consequently, the value of i remains 0.

Compliant Solution (decltype)

In this compliant solution, i is incremented outside of the decltype specifier , so that it is evaluated as desired:.

Code Block
bgColor#ccccff
languagelangcpplangc
#include <iostream>

void f() {
  int i = 0;
  decltype(i) h = 12;
  ++i;
  std::cout << i;
}

Exceptions

EXP32EXP52-CPP-EX1: It is permissible for an expression with side effects to be used as an unevaluated operand in a macro definition or SFINAE context context. While Although these situations rely on the side effects to produce valid code, they typically do not rely on values produced as a result of the side effects.

The following code is an example of compliant code using an unevaluated operand in a macro definition:.

Code Block
bgColor#ccccff
languagelangcpplangc
void small(int x);
void large(long long x);
  
#define m(x)                                     \
  do {                                           \
    if (sizeof(x) == sizeof(int)) {              \
      small(x);                                  \
    } else if (sizeof(x) == sizeof(long long)) { \
      large(x);                                  \
    }                                            \
  } while (0)
  
void f() {
  int i = 0;
  m(++i);
}

The expansion of the macro m will result in the expression ++i being used as an unevaluated operand to sizeof(). However, however the expectation of the programmer at the expansion loci is that i is preincremented only once. Consequently, this is a safe macro and complies with PRE31-C. Avoid side effects in arguments to unsafe macros. Compliance with that rule is especially important for code that follows this exception.

The following code is an example of compliant code using an unevaluated operand in a SFINAE context to determine whether a type can be postfix incremented:.

Code Block
bgColor#ccccff
languagelangcpplangc
#include <iostream>
#include <type_traits>
#include <utility>


template <typename T>
class is_incrementable {
  typedef char one[1];
  typedef char two[2];
  static one &is_incrementable_helper(decltype(std::declval<typename std::remove_cv<T>::type&>()++) *p);
  static two &is_incrementable_helper(...);
  
public:
  static const bool value = sizeof(is_incrementable_helper(nullptr)) == sizeof(one);
};

void f() {
  std::cout << std::boolalpha << is_incrementable<int>::value;
}

In an instantiation of is_incrementable, the use of the postfix increment operator generates side effects which that are used to determine whether the type is postfix incrementable. However, the value result of these side effects is discarded, so the side effects are used only used for SFINAE.

Risk Assessment

If expressions that appear to produce side effects are an unevaluated operand, the results may be different than expected. Depending on how this result is used, it can lead to unintended program behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

EXP32

EXP52-CPP

Low

Unlikely

Low

P3

L3

Automated Detection

Tool

Version

Checker

Description

Astrée

Include Page
Astrée_V
Astrée_V

sizeof
Partially checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC++-EXP52
Clang
Include Page
Clang_V
Clang_V
-Wunevaluated-expression
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.STRUCT.SE.SIZEOF

Side Effects in sizeof

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C++3240, C++3241
Klocwork
Include Page
Klocwork_V
Klocwork_V

MISRA.SIZEOF.SIDE_EFFECT


LDRA tool suite
Include Page
LDRA_V
LDRA_V

54 S, 133 S

Partially implemented

Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_CPP-EXP52-a
CERT_CPP-EXP52-b
CERT_CPP-EXP52-c
CERT_CPP-EXP52-d

-Wunused-value 

CERT_CPP-EXP52-e

The operand of the sizeof operator shall not contain any expression which has side effects
Object designated by a volatile lvalue should not be accessed in the operand of the sizeof operator
The function call that causes the side effect shall not be the operand of the sizeof operator
The operand of the 'typeid' operator shall not contain any expression that has side effects
The operand of the 'typeid' operator shall not contain a function call that causes side effects

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C++: EXP52-CPPChecks for logical operator operand with side effects
RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
sizeof
Partially checked

Related Vulnerabilities

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

Related Guidelines

Bibliography

[ISO/IEC 14882-2014]Clause 5, "Expressions"
Subclause 20.2.5, "Function
template
Template declval


...

Image Added Image Added Image Added