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

Compare with Current View Page History

« Previous Version 25 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 (Pointers)

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 performs a range check to ensure that pos does not exceed the upper bound of the array, specified by table_size, but fails to check the lower bound. Because pos has been declared as a (signed) int, this parameter can assume a negative value, resulting in a write outside the bounds of the memory referenced by table.

#include <cstddef>
 
void insert_in_table(int *table, std::size_t table_size, int pos, int value) {
  if (pos >= table_size) {
    // Handle error
    return;
  }
  table[pos] = value;
}

Compliant Solution (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).

#include <cstddef>
 
void insert_in_table(int *table, std::size_t table_size, std::size_t pos, int value) {
  if (pos >= table_size) {
    // Handle error
    return;
  }
  table[pos] = value;
}

Compliant Solution (Non-Type Templates)

Non-type templates can be used to define functions accepting an array type where the array bounds are deduced at compile time. This compliant solution is functionally equivalent to the previous bounds-checking one, except that it additionally supports calling insert_in_table() with an array of known bounds.

#include <cstddef>
#include <new>

void insert_in_table(int *table, std::size_t table_size, std::size_t pos, int value) { // #1
  if (pos >= table_size) {
    // Handle error
    return;
  }
  table[pos] = value;
}

template <std::size_t N>
void insert_in_table(int (&table)[N], std::size_t pos, int value) { // #2
  insert_in_table(table, N, pos, value);
}
 
void f() {
  // Exposition only
  int table1[100];
  int *table2 = new int[100];
  insert_in_table(table1, 0, 0); // Calls #2
  insert_in_table(table2, 0, 0); // Error, no matching function call
  insert_in_table(table1, 100, 0, 0); // Calls #1
  insert_in_table(table2, 100, 0, 0); // Calls #1
  delete [] table2;
}

Noncompliant Code Example (std::vector)

In this noncompliant code example, a std::vector is used in place of a pointer and size pair. 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 assume a negative value, resulting in a write outside the bounds of the std::vector object.

#include <vector>
 
void insert_in_table(std::vector<int> &table, int pos, int value) {
  if (pos >= table_size) {
    // Handle error
    return;
  }
  table[pos] = value;
}

Compliant Solution (std::vector, 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).

#include <vector>
 
void insert_in_table(std::vector<int> &table, std::size_t pos, int value) {
  if (pos >= table_size) {
    // Handle error
    return;
  }
  table[pos] = value;
}

Compliant Solution (std::vector::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. The insert_in_table() function is declared with noexcept(false) in compliance with ERR30-CPP. Try to recover gracefully from unexpected errors.

#include <vector>
 
void insert_in_table(std::vector<int> &table, std::size_t pos, int value) noexcept(false) {
  table.at(pos) = value;
}

Noncompliant Code Example (Iterators)

In this noncompliant code example, it is possible that the function is given a valid iterator, but that the iterator is not within a valid range. For instance, if f() were called with iterators obtained from an empty container, the end() iterator could be improperly dereferenced.

#include <iterator>
 
template <typename ForwardIterator>
void f_imp(ForwardIterator B, ForwardIterator E, int Val, std::forward_iterator_tag) {
  do {
    *B++ = Val;
  } while (B != E);
}

template <typename ForwardIterator>
void f(ForwardIterator B, ForwardIterator E, int Val) {
  typename std::iterator_traits<ForwardIterator>::iterator_category Cat;
  f_imp(B, E, Val, Cat);
}

Compliant Solution

This compliant solution tests for iterator validity before attempting to dereference the forward iterator:

#include <iterator>
 
template <typename ForwardIterator>
void f_imp(ForwardIterator B, ForwardIterator E, int Val, std::forward_iterator_tag) {
  while (B != E) {
    *B++ = Val;
  }
}

template <typename ForwardIterator>
void f(ForwardIterator B, ForwardIterator E, int Val) {
  typename std::iterator_traits<ForwardIterator>::iterator_category Cat;
  f_imp(B, E, Val, Cat);
}

Risk Assessment

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

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CTR30-CPP

High

Likely

High

P9

L2

Automated Detection

Tool

Version

Checker

Description

    

Related Vulnerabilities

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

Related Guidelines

CERT C Coding Standard ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
MITRE CWECWE 119, Failure to Constrain Operations within the Bounds of a Memory Buffer
CWE 129, Improper Validation of Array Index

Bibliography

[ISO/IEC 14882-2014]

23, "Containers Library"
24.2.1, "In General" 

[Viega 05]Section 5.2.13, "Unchecked Array Indexing"
[ISO/IEC PDTR 24772]"XYX Boundary Beginning Violation," "XYY Wrap-around Error," and "XYZ Unchecked Array Indexing"

 

CTR04-CPP. Assume responsibility for cleaning up data referenced by a container of pointers      006. Containers (CTR)      

  • No labels