Main Content

CERT C: Rule EXP43-C

Avoid undefined behavior when using restrict-qualified pointers

Description

Rule Definition

Avoid undefined behavior when using restrict-qualified pointers.1

Polyspace Implementation

The rule checker checks for Overlapping access by restrict-qualified pointers.

Examples

expand all

Issue

Overlapping access by restrict-qualified pointers occurs when any of these is true:

  • Two restrict-qualified pointers modify objects that have overlapping memory addresses.

  • In a function, one or more const restrict-qualified pointer might modify a nonconst restrict-qualified pointer but when calling the function, the const and nonconst arguments are the same or are derived from the same pointer.

  • A standard library function is called by using restrict-qualified pointers that overlap.

  • A restrict-qualified pointer is assigned to another restrict-qualified pointer within the same scope.

Risk

The restrict qualifier on a pointer implies that within a block, only this pointer (or other pointers created from this pointer) can access the pointed object. You cannot create a second pointer independently of the restrict-qualified pointer to point to the object.

This specification requires that two restrict-qualified pointers cannot point to the same or overlapping objects. Two restrict-qualified pointers accessing the same memory address or object results in undefined behavior.

Fix

If you assign a restrict-qualified pointer to another pointer, make sure that the destination pointer itself is not restrict-qualified. The restrict qualifier assists the compiler in optimizing the code. Removing all instances of this qualifier does not change the observable code behavior.

Example — Assignment Between restrict-qualified Pointers in the Same Scope
int *restrict rptr1;   
int *restrict rptr2;  
int *         ptr; 
extern int arr[];

void func (void)
{
  arr[0] = 0;
  arr[1] = 1;
  rptr1 = &arr[0];
  rptr2 = &arr[1];
  rptr2 = rptr1;  //Non-compliant
  ptr   = rptr1;  //Compliant
  /* ... */

}

In this example, rptr1 and rptr2 are restrict-qualified pointers that point to different locations in the same array arr. Assigning one such restrict-qualified pointer to another in the same scope causes a rule violation.

Example — restrict-Qualified Function Parameters
#include <stddef.h>
#include <stdio.h>
void addArray (size_t n, int *restrict res,
               const int *restrict lhs, const int *restrict rhs)
{
  for (size_t i = 0; i < n; ++i) {
    res[i] = lhs[i] + rhs[i];
  }
}
void foo (void)
{
  int a[100];
  memset(&a, 0, 100);
  addArray (100, a, a, a);//Noncompliant
}

In this example, the function addArray() is defined with three restrict qualified parameters lhs, rhs, and res. The parameters lhs and rhs are const restrict pointers. The function addArray() is then invoked by using the same pointer a as all three parameters. As a result, the const restrict qualified pointers lhs and rhs might attempt to access the memory associated with the non-const restrict qualified pointer res. This overlapping access between lhs and res as well as that between rhs and res are undefined behaviors. Polyspace® raises two violations on the function call.

Example — Invoking Library Functions by Using restrict-Qualified Pointers
#include <string.h>
  
void func(void) {
  char c_str[]= "test string";
  char *ptr1 = c_str;
  char *ptr2;
 
  ptr2 = ptr1 + 3;
  /* Undefined behavior because of overlapping objects */
  memcpy(ptr2, ptr1, 6);//Noncompliant
  /* ... */
}

In this example, the function memcpy has two restrict-qualified pointers as input parameters This function copies six bytes from the location pointed to by ptr1 into the location pointed to by ptr2. Because the distance between ptr1 and ptr2 is three bytes, the memcpy function call results in two restrict-qualified pointers attempting to modify overlapping memory. This overlapping access results in undefined behavior. Polyspace flags the call to memcpy.

Example — Assignments Between Restricted Pointers
void func(void) {
  int *restrict p1;
  int *restrict p2 = p1; /* Undefined behavior */ //Noncompliant
 }

In this example, the restrict-qualified pointer p1 is assigned to another restrict-qualified pointer in the same scope. Such assignments result in undefined behavior, which Polyspace flags. To resolve the issue, declare p2 in a separate nested scope. For example:

void func(void) {
  int *restrict p1;
  {
      int *restrict p2 = p1;//Compliant
  }
 }

Check Information

Group: Rule 03. Expressions (EXP)

Version History

Introduced in R2019a

expand all


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.