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

Compare with Current View Page History

« Previous Version 13 Next »

Ensuring that array references are within the bounds of the array is almost entirely the responsibility of the programmer. Likewise, when using STL vectors, the programmer is responsible for ensuring integer indexes are within the bounds of the vector.

Noncompliant Code Example (Arrays)

This noncompliant code example shows a function insert_in_table() that has two int paramters, pos and value, both of which can be influenced by data originating from untrusted sources. The function uses a global variable table to determine if storage has been allocated for an array of 100 integer elements and allocates the memory if it has not already been allocated.

enum { TABLESIZE = 100 };

int *table = NULL;

int insert_in_table(int pos, int value){
  if (!table) {
    table = new int[TABLESIZE];
  }
  if (pos >= TABLESIZE) {
    return -1;
  }
  table[pos] = value;
  return 0;
}

The function performs a range check to ensure that pos does not exceed the upper bound of the array but fails to check the lower bound for table. Because pos has been declared as a (signed) int, this parameter can easily assume a negative value, resulting in a write outside the bounds of the memory referenced by table.

Compliant Solution (Arrays)

In this compliant solution, the parameter pos is declared as size_t, which prevents passing of negative arguments (see INT01-CPP. Use rsize_t or size_t for all integer values representing the size of an object).

enum { TABLESIZE = 100 };

int *table = NULL;

int insert_in_table(size_t pos, int value){
  if (!table) {
    table = new int[TABLESIZE];
  }
  if (pos >= TABLESIZE) {
    return -1;
  }
  table[pos] = value;
  return 0;
}

Compliant Solution (Array Templates)

Specialized function templates can be used to define functions that accept an array of a generic type T of size n. The compiler can perform template argument deduction for function templates to properly deduce both the type and size. This compliant solution defines a function template for a function clear() that takes a template parameter array[] of T elements and an actual length parameter of type size_t. This is not particularly useful yet, as we have already seen that passing an array with an explicit size parameter is a common (but error prone) idiom. However, you can also define a specialization of the function template that includes a template parameter n of type size_t in addition to the original type parameter. The inline function clear() has one parameter: an array of type T elements of fixed length n.

template <typename T>
void clear(T array[], size_t n) {
  for (size_t i = 0; i < n; ++i) {
    array[i] = 0;
  }
}

template <typename T, size_t n>
inline void clear(T (&array)[n]) {
  clear(array, n);
}

int int_array[12];

clear(int_array); // deduce T is int, and that n is 12

The function template and specialized function template can be used in a straightforward manner. This example declares an array of 12 integers named int_array and invokes the clear() function passing int_array as an argument. The compiler matches this invocation to inline void clear(T (&array)[n]) because this definition most closely matches the actual argument type of array of int. The compiler deduces that the type T is int and that n is 12, separating the size n from the pointer to the array of int before invoking the function template for clear(). This use of specialized function templates guarantees that the clear() function has the correct array size.

Noncompliant Code Example (Vectors)

The above code examples perform the same when working with vectors.

vector<int> table;

int insert_in_table(int pos, int value){
  if (pos >= table.size()) {
    return -1;
  }
  table[pos] = value;
  return 0;
}

The function performs a range check to ensure that pos does not exceed the upper bound of the array but fails to check the lower bound for table. Because pos has been declared as a (signed) int, this parameter can easily assume a negative value, resulting in a write outside the bounds of the memory referenced by table.

Compliant Solution (Vectors, size_t)

In this compliant solution, the parameter pos is declared as size_t, which prevents passing of negative arguments (see INT01-CPP. Use rsize_t or size_t for all integer values representing the size of an object).

vector<int> table;

int insert_in_table(size_t pos, int value){
  if (pos >= table.size()) {
    return -1;
  }
  table[pos] = value;
  return 0;
}

Compliant Solution (Vectors, at())

In this compliant solution, access to the vector is accomplished with the at() method. This method provides bounds checking, throwing an out_of_range exception if pos is not a valid index value.

vector<int> table;

int insert_in_table(size_t pos, int value){
  table.at(pos) = value;
  return 0;
}

Risk Assessment

Using an invalid array or vector index can result in an arbitrary memory overwrite or abnormal program termination.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ARR30-CPP

high

likely

high

P9

L2

Automated Detection

The Coverity Prevent Version 5.0 NEGATIVE_RETUENS checker can detect where negative value is used to index an array in a read/write operation.

The LDRA tool suite Version 7.6.0 can detect violations of this rule.

Klocwork Version 8.0.4.16 can detect violations of this rule with the ABR, ABV.TAINTED, and SV.TAINTED.INDEX_ACCESS checkers.

Compass/ROSE can detect some violations of this rule. In particular, if a signed index to an array is being verified, it ensures that the value is also compared against 0.

Related Vulnerabilities

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

Other Languages

This rule appears in the C Secure Coding Standard as ARR30-C. Guarantee that array indices are within the valid range.

References

[ISO/IEC PDTR 24772] "XYX Boundary Beginning Violation," "XYY Wrap-around Error," and "XYZ Unchecked Array Indexing"
[MITRE] CWE ID 119, "Failure to Constrain Operations within the Bounds of a Memory Buffer"
[MITRE] CWE ID 129, "Improper Validation of Array Index"
[Viega 05] Section 5.2.13, "Unchecked array indexing"


ARR02-CPP. Explicitly specify array bounds, even if implicitly defined by an initializer      06. Arrays and the STL (ARR)      ARR31-CPP. Use consistent array notation across all source files

  • No labels