Main Content

MISRA C:2023 Rule 13.2

The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders and shall be independent from thread interleaving

Since R2024a

Description

Rule Definition

The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders and shall be independent from thread interleaving.

Rationale

If an expression results in different values depending on the order of evaluation, its value becomes implementation-defined.

If an expression results in different values depending on order of thread-interleaving, then the value is unpredictable since the C standard does not specify any order for thread interleaving. Such unpredictable behavior implies your code might contain data race conditions, which is undefined behavior.

Polyspace Implementation

The rule checker reports a violation if an expression satisfies any of these conditions:

  • The same variable is modified more than once in the expression or it is both read and written.

  • The expression allows more than one order of evaluation.

  • The expression contains a single volatile object that occurs multiple times.

  • The expression contains more than one volatile object.

Because volatile objects can change their value at anytime, an expression containing multiple volatile variables or multiple instances of the same volatile variable might have different results depending on the order of evaluation.

Troubleshooting

If you expect a rule violation but do not see it, refer to Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

int a[10], b[10];
#define COPY_ELEMENT(index) (a[(index)]=b[(index)])

void main () {
	int i=0, k=0;

	COPY_ELEMENT (k);         /* Compliant */
	COPY_ELEMENT (i++); /* Noncompliant  */
}

In this example, the rule is violated by the statement COPY_ELEMENT(i++) because i++ occurs twice and the order of evaluation of the two expressions is unspecified.

void f (unsigned int param1, unsigned int param2) {}

void main () {
    unsigned int i=0;
    f ( i++, i );                 /* Non-compliant */
}

In this example, the rule is violated because it is unspecified whether the operation i++ occurs before or after the second argument is passed to f. The call f(i++,i) can translate to either f(0,0) or f(0,1).

struct {
	volatile float x; 
	volatile float y; 
} volData;

float xCopy;
float yCopy;
float res, res2;

void function4(void) {
	res = volData.x + volData.y;         //Noncompliant
	res = volData.x * volData.x;	  //Noncompliant
	xCopy = volData.x;
	yCopy = volData.y;
	res = xCopy + yCopy;  //Compliant
}  

In this example, the expression volData.x + volData.y is noncompliant because the expression involves multiple volatile objects. The expression consists of three operations: accessing the value of volData.x, accessing the value of volData.y, and the addition. The values of the volatile fields x and y in the volData structure might change at any time. The value of res might vary depending on which variable is read first. Because the C standard does not specify the order in which the variables are read, the value of res might depend on the hardware and software that you use. Polyspace® flags one of the volatile objects in the expression. Similarly, Polyspace flags one of the volatile objects in the expression volData.x * volData.x.

To avoid the violation, assign the volatile variables to nonvolatile temporary variables and use these temporary variables in the expression.

Check Information

Group: Side Effects
Category: Required
AGC Category: Required

Version History

Introduced in R2024a