Main Content

CWE Rule 768

Incorrect Circuit Evaluation

Since R2026a

Description

Incorrect Circuit Evaluation

Polyspace Implementation

The rule checker checks for the issue Right hand operand of a logical && or || operator contains persistent side effects.

Examples

expand all

Issue

This issue occurs when the right side of a logical || or && operator has persistent side effects. For instance, if the right side contains a function call and the function modifies a global variable, Polyspace® reports a violation.

Polyspace does not report a violation if the right side contains a call to a pure function, that is, a function without side effects. The checker considers a function as pure if the function performs only simple operations such as:

  • Reading a nonvolatile parameter or global variable

  • Writing to a local variable

In addition to simple operations, if the function contains a call to another function, Polyspace attempts to determine if the callee is a pure function. If Polyspace determines that the callee is a pure function, then the calling function is considered a pure function (as long as the other operations in the calling function are simple operations).

Polyspace does not consider a function as pure if the function does one of the following:

  • Writes to a global variable or the dereference of a parameter

  • Reads or writes to a volatile variable, or contains an asm block

To determine if a function is pure, Polyspace searches for the function definition within the same translation unit as the function call (a translation unit is a source file plus all headers included in the source). If a function definition is not found in the current translation unit, the checker does not report a violation of this rule. The checker also does not analyze functions called via function pointers.

If the right operand of the logical || or && operator invokes a function by using a function pointer, Polyspace cannot determine whether the invoked function has side effects. Polyspace does not report a violation in this case.

Risk

The right operand of the || operator is not evaluated if the left operand is true. The right operand of the && operator is not evaluated if the left operand is false. In these cases, if the right operand modifies the value of a variable, the modification does not take place.

Fix

Avoid relying on side effects in logical operations.

Example — Short-circuit behavior of logical AND operator

In this example, the operand (accounts[index].role = ROLE_USER) is the right operand of a logical operation and modifies an array. If the left operand --index evaluates to false, the right operand is not evaluated and the assignment does not happen, which can lead to an unexpected result. Polyspace reports a violation.

#include <stdio.h>
#include <stdlib.h>

#define ROLE_ADMIN 0
#define ROLE_USER 1

typedef struct {
    int role;
    int identifier;
} account_t;

account_t *Create_User_Accounts(int total_accounts) {
    account_t *accounts = (account_t *)calloc(total_accounts, sizeof(account_t));
    int index = total_accounts;
    while (--index && (accounts[index].role = ROLE_USER)) { //Noncompliant
        accounts[index].identifier = index;
    }
    return accounts;
}

int main() {
    account_t *sample;
    int j;
    sample = Create_User_Accounts(25);
    for (j = 0; j < 25; j++)
        printf("Account %d has role level %d\n", sample[j].identifier, sample[j].role);
    free(sample);
    return 0;
}

Correction — Remove Reliance on Side Effects

To fix this violation, refactor your code to remove the assignment operation from the right side of the logical && operator. One possible solution is to change the while loop condition to a pure comparison and move all assignments within the body of the loop.

#include <stdio.h>
#include <stdlib.h>

#define ROLE_ADMIN 0
#define ROLE_USER 1

typedef struct {
    int role;
    int identifier;
} account_t;

account_t *Create_User_Accounts(int total_accounts) {
    account_t *accounts = (account_t *)calloc(total_accounts, sizeof(account_t));
    int index = total_accounts;
    while (index!=0) {  //Compliant
        accounts[index].role = ROLE_USER;
        accounts[index].identifier = index;
        index--;
    }
    return accounts;
}

int main() {
    account_t *sample;
    int j;
    sample = Create_User_Accounts(25);
    for (j = 0; j < 25; j++)
        printf("Account %d has role level %d\n", sample[j].identifier, sample[j].role);
    free(sample);
    return 0;
}

Check Information

Category: Others
PQL Name: std.cwe_native.R768

Version History

Introduced in R2026a