Some operators do not evaluate their operands beyond the type information they provide. When using one of these operators, do not pass an operand which would otherwise yield a side effect, as the side effect will not be generated.
The sizeof
operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. In most cases, the operand is not evaluated. A possible exception is when the type of the operand is a variable length array type (VLA) the expression is evaluated. When part of the operand of the sizeof
operator is a VLA type and when changing the value of the VLA's size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated. See unspecified behavior 22 in Annex J of the C Standard.
The operands passed to _Generic
and _Alignof
are never evaluated.
Providing an expression that appears to produce side effects may be misleading to programmers who are not aware that these expressions are not evaluated, and in the case of a VLA used in sizeof
, have unspecified results. As a result, programmers may make invalid assumptions about program state, leading to errors and possible software vulnerabilities.
Noncompliant Code Example (sizeof
)
In this noncompliant code example, the expression a++
is not evaluated, and the side effects in the expression are not executed:
void func(void) { int a = 14; int b = sizeof(a++); }
Consequently, the value of a
after b
has been initialized is 14.
Compliant Solution (sizeof
)
In this compliant solution, the variable a
is incremented:
void func(void) { int a = 14; int b = sizeof(a); ++a; }
Noncompliant Code Example (sizeof
, VLA)
In this noncompliant code example, the expression ++n
in the initialization expression of a
must be evaluated because its value affects the size of the VLA operand of the sizeof
operator. However, because the expression ++n % 1
evaluates to 0
, regardless of the value of n
, its value does not affect the result of the sizeof
operator. Consequently, it is unspecified whether or not n
is incremented.
#include <stddef.h> void f(size_t n) { /* n must be incremented */ size_t a = sizeof(int[++n]); /* n need not be incremented */ size_t b = sizeof(int[++n % 1 + 1]); /* ... */ }
Compliant Solution (sizeof
, VLA)
This compliant solution avoids changing the value of the variable n
used in the sizeof
expression and instead increments it safely outside of it:
#include <stddef.h> void f(size_t n) { size_t a = sizeof(int[n + 1]); ++n; size_t b = sizeof(int[n % 1 + 1]); ++n; /* ... */ }
Noncompliant Code Example (_Generic
)
This noncompliant solution attempts to modify a variable's value as part of the _Generic
association list. The user may have expected the value of a
to be 2
because the type of the variable is int
, but because _Generic
does not evaluate its operands, the result is undefined behavior.
#define S(val) _Generic(val, int : val = 2, \ short : val = 3, \ default : val = 1) void func(void) { int a = 0; S(a); }
Compliant Solution (_Generic
)
This compliant solution uses the result of the _Generic
operator to assign the correct value to a
.
#define S(val) _Generic(val, int : 2, \ short : 3, \ default : 1) void func(void) { int a = 0; a = S(a); }
Noncompliant Code Example (_Alignof
)
This noncompliant code example attempts to modify a variable while getting its default alignment value. The user may have expected val
to be incremented as part of the _Alignof
expression, but because _Alignof
does not evaluate its operand, the result is undefined behavior.
#include <stddef.h> void func(void) { int val = 0; /* ... */ size_t align = _Alignof(++val); /* ... */ }
Compliant Solution (_Alignof
)
The compliant solution moves the expression out of the _Alignof
operator.
#include <stddef.h> void func(void) { int val = 0; /* ... */ ++val; int align = _Alignof(val); /* ... */ }
Risk Assessment
If expressions that appear to produce side effects are supplied to an operator that does not evaluate its operands, 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 |
---|---|---|---|---|---|
EXP44-C | Low | Unlikely | Low | P3 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
|
|
| |
1.2 | CC2.EXP06 | Fully implemented | |
9.7.1 | 54 S | Fully implemented | |
PRQA QA-C | Unable to render {include} The included page could not be found. | 3307 | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard | EXP06-CPP. Operands to the sizeof operator should not contain side effects |