Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Edits; reviewed

An object that is accessed through a restrict-qualified pointer has a special association with that pointer. This association requires that all accesses to that object use, directly or indirectly, the value of that particular pointer. The intended use of the restrict qualifier is to promote optimization, and deleting all instances of the qualifier from a program does not change its meaning (that is, observable behavior). In the absence of this qualifier, other pointers can alias this object. Caching the value in an object designated through a restrict-qualified pointer is safe at the beginning of the block in which the pointer is declared, because no pre-existing aliases may also be used to reference that object. The cached value must be restored to the object by the end of the block, where pre-existing aliases again become available. New aliases may be formed within the block, but these must all depend on the value of the restrict-qualified pointer, so that they can be identified and adjusted to refer to the cached value. For a restrict-qualified pointer at file scope, the block is the body of each function in the file [Douglas Walls 2006]. Developers should be aware that C++ does not support the restrict qualifier, however, some C++ compiler vendors support a an equivalent qualifier. 

Annex J of the C Standard [ISO/IEC 9899:2011] identifies the following undefined behavior 68:

...

This is an oversimplification however, and it is important to review the formal definition of restrict in subclause 6.7.3.1 of the C Standard to propertly properly understand undefined behaviors associated with the use of restrict-qualified pointer .

...

Code Block
bgColor#FFCCCC
langc
int * restrict a;
int * restrict b;

extern int c[];
 
int main(void) {
  c[0] = 17; 
  c[1] = 18;
  a = &c[0]; 
  b = &c[1];
  a = b; /* undefinedUndefined behavior */

  /* ... */
}

Compliant Solution

One way to eliminate the undefined behavior is simply to remove the restrict-qualification from the affected pointers. 

Code Block
bgColor#ccccff
langc
int * a;
int * b;

extern int c[];
 
int main(void) {
  c[0] = 17; 
  c[1] = 18;
  a = &c[0]; 
  b = &c[1];
  a = b; /* validValid defined behavior */

  /* ... */
}

restrict-qualified pointers Function Parameters

When calling functions that have restrict qualified function parameters, it is important that pointers do not reference overlapping objects If one if one or more of the objects modify memory. Thus it is important to understand the semantics of the function being called.

...

Code Block
bgColor#FFCCCC
langc
#include <stddef.h>
void f(size_t n, int * restrict p, int * restrict q) {
  while (n-- > 0) {
    *p++ = *q++;
  }
}
 
void g(void) {
  extern int d[100];

  /* ... */
  f(50, d + 1, d); /* undefinedUndefined behavior */
}

The function g() declares an array d consisting of 100 int values and then invokes f() to copy memory from one area of the array to another. This call has undefined behavior because each of d[1] through d[49] is accessed through both p  and q .

...

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
void f(intsize_t n, int * restrict p, int * restrict q) {
   while (n-- > 0) {
     *p++ = *q++;
  } 
}
 
void g(void) {
  extern int d[100];

  /* ... */
  f(50, d + 50, d); /* validValid defined behavior  */
}

Noncompliant Code Example

In this noncompliant code example, the function hadd() adds the integer array referenced by the restrict-qualified pointers q lhs to the integer array referenced by the restrict-qualified pointer rrhs and stores the result in the restrict-qualified pointer referenced by p res. The call hadd(100, a, a, a) has undefined behavior because the object modified by p res is accessed by q lhs and r rhs.

Code Block
bgColor#FFCCCC
langc
#include <stddef.h>
 
void hadd(size_t n, int * restrict pres, int * restrict q,lhs,
       int * restrict rrhs) {
  for (size_t i = 0; i < n; i++i) {
    pres[i] = qlhs[i] + rrhs[i];
  }
}
 
void jf(void) {

  int a[100]; 
  hadd(100, a, a, a); /* undefinedUndefined behavior */
}

The function gf() declares an array d array a consisting of 100 int values and then invokes fadd() to copy memory from one area of the array to another. This call has undefined behavior because each of da[1] through da[49] is accessed through both p and qboth lhs and rhs .

Compliant Solution

In this compliant solution, an unmodified object is aliased through two restricted pointers. Because a and b are disjoint arrays, a call of the form hadd(100, a, b, b) has defined behavior, because array b is not modified within function hadd.

Code Block
bgColor#ccccff
langc
#include <stddef.h>
void hadd(size_t n, int * restrict pres, int * restrict q,lhs,
         int * restrict rrhs) {
  for (size_t i = 0; i < n; i++i) {
    pres[i] = qlhs[i] + rrhs[i];
  }
}
 
void jf(void) {
   int a[100]; 
   int b[100];
   hadd(100, a, b, b); /* validValid defined behavior  */
}

Invoking Library Functions with restrict-qualified Pointers

...

Code Block
bgColor#FFCCCC
langc
#include <string.h>
 
void func(void) {
  char c_str[]= "test string";
  char *ptr1 = c_str;
  char *ptr2;

  ptr2 = ptr1 + 3;
   memcpy(ptr2, ptr1, 6); /* undefined/* Undefined behavior due to overlapping objects */
  memcpy(ptr2, ptr1, 6);
  
  /* ... */
}

Compliant Solution

In this compliant solution, the call to memcpy() is replaced with a call to memmove(). The memmove() function performs the same operation as memcpy() when the memory regions do not overlap. When the memory regions do overlap, the n characters from the object pointed to by the source (ptr1) are first copied into a temporary array of n characters that does not overlap the objects pointed to by the destination (ptr2) or the source. The n characters from the temporary array are then copied into the object pointed to by the destination.

Code Block
bgColor#ccccff
langc
#include <string.h>

void func(void) {
  char c_str[]= "test string";
  char *ptr1 = c_str;
  char *ptr2;

  ptr2 = ptr1 + 3;
  memmove(ptr2, ptr1, 6);  /* Replace call to memcpy() */

  /* ... */
}

...

Code Block
int printf(
  const char * restrict format,
  /* ... */
);

 
int scanf(
  const char * restrict format,
  /* ... */
);

 
int sprintf(
  char * restrict s,
  const char * restrict format,
  /* ... */
);

 
int snprintf(
  char * restrict s,
  size_t n,
  const char * restrict format,
  /* ... */
);

...

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
 
/* ...  */
char format[100] = "%s";
int i; 
float x;
void func() {
  int i;
  float x
  char format[100] = "%s";
  /* Undefined behavior */
  int n = scanf(format, format + 2, &i, &x);
 
  /* undefined... behavior */
}

Compliant Solution

The same results can be achieved as shown in this compliant solution.

Code Block
bgColor#ccccff
langc
#include <stdio.h>
 
/* ... */
void func(void) {
  int i;
 
 float x;
  int n = scanf("%d%f", &i, &x); /* valid defined behavior  Valid defined behavior  */
 
  /* ... */ 
}

Outer to-inner assignments between restricted pointers

The assignment between restricted pointers declared in a inner nested a block from a outer block have has well defined behavior.

Noncompliant Code Example

...

Code Block
bgColor#FFCCCC
langc
 void func(void) {
  int * restrict p1;
  int * restrict q1;

  int * restrict p2 = p1; /* undefinedUndefined behavior */ 
  int * restrict q2 = q1; /* undefinedUndefined behavior */ 
 }

Compliant Solution 

...

Code Block
bgColor#ccccff
langc
void func(void) {
  int * restrict p1;   
  int * restrict q1;
  {  /* addedAdded inner block begin */
    int * restrict p2 = p1;  /* validValid defined behavior  */    
    int * restrict q2 = q1;  /* validValid defined behavior  */ 
    ...
  } /* added inner block end */
}

Risk Assessment

The incorrect use of restict restrict-qualified pointers can result in undefined behavior that might be exploited to cause data integrity violations.

...

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

Automated Detection

Tool

Version

Checker

Description

LDRA tool suite

Include Page
LDRA_V
LDRA_V

480 S 489 S

Partially implemented

Related Guidelines

CERT C Secure Coding StandardFIO30-C. Exclude user input from format strings 
ISO/IEC TR 24772:2013Passing Parameters and Return Values [CSJ]
ISO/IEC TS 17961Passing pointers into the same object as arguments to different restrict-qualified parameters [restrict]

Bibliography

[ISO/IEC 9899:2011]Subclause 6.7.3.1, "Formal Definition of restrict
[Walls 2006]Douglas Walls.  How to Use the Qualifier in C.  Sun ONE Tools Group, Sun Microsystems, July 2003 (revised March 2006)

...

...