You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 56 Next »

It is appropriate to perform pointer arithmetic only on pointers that reference elements of array objects.

Subclause 6.5.6 of the C Standard [ISO/IEC 9899:2011] states the following about pointer arithmetic:

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression.

Noncompliant Code Example

In this noncompliant code example, the programmer tries to access elements of the structure using pointer arithmetic. This practice is dangerous because fields in a structure are not guaranteed to be contiguous.

struct numbers {
  short num_a;
  short num_b;
  short num_c;
};

int sum_numbers(const struct numbers *numb){
  int total = 0;
  const short *numb_ptr;

  for (numb_ptr = &numb->num_a;
       numb_ptr <= &numb->num_c;
       numb_ptr++) {
    total += *(numb_ptr);
  }

  return total;
}

int main(void) {
  struct numbers my_numbers = { 1, 2, 3 };
  sum_numbers(&my_numbers);
  return 0;
}

Compliant Solution

It is possible to use the -> operator to dereference each element of the structure:

total = numb->num_a + numb->num_b + numb->num_c;

However, this solution is likely to cause exactly the sort of painful experience the programmer who wrote the noncompliant code example was trying to avoid.

A better solution is to use an array, as in this compliant solution:

#include <stddef.h>
 
 
int sum_numbers(const short *numb, size_t dim) {
  int total = 0;
  const short *numb_ptr;

  for (numb_ptr = numb; numb_ptr < numb + dim; numb_ptr++) {
    total += *(numb_ptr);
  }

  return total;
}

int main(void) {
  short my_numbers[9] = { 1, 2, 3 };
  sum_numbers(my_numbers,
              sizeof(my_numbers)/sizeof(my_numbers[0]));
  return 0;
}

Array elements are guaranteed to be contiguous in memory, so this solution is completely portable.

Exceptions

ARR37-EX1: All non-array objects in memory can be considered an array of one element. Adding one to such a pointer yields a pointer one element past the array, and subtracting one from that pointer yields the original pointer. This allows for code such as:

#include <stdlib.h>
#include <string.h>
 
struct s {
  char *str;
  /* Other fields */
};
 
struct s *create_s(const char *str) {
  struct s *ret;
  size_t len = strlen(str) + 1;
   
  ret = (struct s *)malloc(sizeof(struct s) + len);
  if (ret != NULL) {
    ret->str = (char *)(ret + 1);
    memcpy(ret + 1, str, len);
  }
  return ret;
}

Risk Assessment

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ARR37-C

Medium

Probable

Medium

P8

L2

Automated Detection

Tool

Version

Checker

Description

Compass/ROSE

 

 

 

Related Vulnerabilities

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

Related Guidelines

Bibliography

 


 

 

  • No labels