Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: REM Cost Reform

Wiki MarkupThe incorrect use of arrays has traditionally been a source of exploitable vulnerabilities. Elements referenced within an array using the subscript operator \[\] are not checked unless the programmer provides adequate bounds checking. As a result, the expression {{array \ [pos\] = value}} can be used by an attacker to transfer control to arbitrary code.

Wiki MarkupIf the attacker can control the values of both {{pos}} and {{value}} in the expression {{array \[pos\] = value}}, he or she can perform an arbitrary write (overwrite other storage locations with contents of his or her choice). The consequences range from changing a variable used to determine what permissions the program grants to executing arbitrary code with the permissions of the vulnerable process. Arrays are also a common source of buffer overflows when iterators exceed the bounds of the An attacker who can control the values of both pos and value in the expression array [pos] = value can perform an arbitrary write (which is when the attacker overwrites other storage locations with different content). The consequences range from changing a variable used to determine what permissions the program grants to executing arbitrary code with the permissions of the vulnerable process. Arrays are also a common source of buffer overflows when iterators exceed the bounds of the array.

An array is a series of objects, all of which are the same size and type. Each object in an array is called an array element. The entire array is stored contiguously in memory (that is, there are no gaps between elements). Arrays are commonly used to represent a sequence of elements where random access is important but there is little or no need to insert new elements into the sequence (which can be an expensive operation with arrays).

Arrays containing a constant number of elements can be declared as follows:

Code Block

enum { ARRAY_SIZE = 12 };
int disarray[ARRAY_SIZE];

These statements allocate storage for an array of 12 integers referenced by dis array. Arrays are indexed from 0..n-1 (where n represents an array bound). Arrays can also be declared as follows:

Code Block

int itaarray[];

This array is called an incomplete type because the size is unknown. If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. At the end of its initializer list, the array no longer has incomplete type.

Code Block

int itaarray[] = { 1, 2 };

While Although these declarations work fine when the size of the array is known at compilation compile time, it is not possible to declare an array in this fashion when the size can be determined only at runtime. The C99 standard C Standard adds support for variable - length arrays or arrays whose size is determined at runtime. Before the introduction of variable - length arrays in C99, however, these "arrays" were typically implemented as pointers to their respective element types allocated using malloc(), as shown in this example.:

Code Block

int *datdis = (int *)malloc(ARRAY_SIZE * sizeof(int));

Always check that malloc() returns a non-null pointer, as per ERR33-C. Detect and handle standard library errors.

It is important to retain any pointer value returned by malloc() so that the referenced memory may eventually be deallocated. One possible way of preserving to preserve such a value is to use a constant pointer.:

Code Block

int * const dat = (int * const)malloc(
  ARRAY_SIZE * sizeof(int)
);
/* ... */
free(dat);
dat = NULL;

Below we consider some techniques for array initialization.  Both dis and dat arrays can be initialized as follows:

Code Block

for (i = 0; i < ARRAY_SIZE; i++) {
   dis[i] = 42; /* Assigns 42 to each element; of dis */ 
   dat[i] = 42; /* ... Assigns 42 to each element of dat */
}

The dat dis array can also be initialized as follows:

Code Block

for (i = 0; i < ARRAY_SIZE; i++) {
   *datdis = 42;
   datdis++;
}
datdis -= ARRAY_SIZE;

The dis This technique, however, will not work for dat.  The dat identifier cannot be incremented , so the expression dis++ results in (produces a fatal compilation error. Both arrays can be initialized as follows), as it was declared with type int * const.  This problem can be circumvented by copying dat into a separate pointer:

Code Block

int *p = disdat;
for (i = 0; i < ARRAY_SIZE; i++)  {
  *p = 42; /* Assigns 42 to each element */
  p++;
}

The variable p is declared as a pointer to an integer, initialized with the value stored in dat, and then incremented in the loop. This technique can be used to initialize both arrays, and is a better style of programming than incrementing the original pointer to the array because it does not change the pointer (e.g., dis++, in the above example), as it avoids having to reset the pointer back to the start of the array after the loop completes. 

Wiki MarkupObviously, there is a relationship between array subscripts {{\[\]}} and pointers. The expression {{dis\[i\]}} is equivalent to {{\*(dis+i)}}. In other words, if {{dis}} is an array object (equivalently, a pointer to the initial element of an array object) and {{i}} is an integer, {{dis\[i\]}} designates the {{i{}}}th element of {{dis}} (counting from zero). In fact, because {{\ for all integral values of i. In other words, if dis is an array object (equivalently, a pointer to the initial element of an array object) and i is an integer, dis[i] designates the ith element of dis. In fact, because *(dis+i)}} can be expressed as {{\*(i+dis)}}, the expression {{dis\[i\]}} can be represented as {{i\[dis\]}}, although doing so is not encouraged. Wiki MarkupThe initial element of an array is accessed using an index of zero; for example, {{dat\[0\]}} references the first element of {{dat}} array. The {{dat}} identifier points to the start of the array, so adding zero is inconsequential in that {{\*(dat+i)}} is equivalent to {{\*(dat+0)}}, which is equivalent to {{\*(dat)}}Because array indices are zero-based, the first element is designated as dis[0], or equivalently as *(dis+0) or simply *dis.

Risk Assessment

Arrays are a common source of vulnerabilities in C language programs because they are frequently used but not always fully understood.

Recommendation

Severity

Likelihood

Remediation Cost

Detectable

Repairable

Priority

Level

ARR00-C

high

High

Probable

probable

No

high

No

P6

L2

Automated Detection

Tool

Version

Checker

Description

CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.CAST.ARRAY.TEMP

Array to Pointer Conversion on Temporary Object
Klocwork
Include Page
Klocwork_V
Klocwork_V
ABV.ANY_SIZE_ARRAY
ABV.GENERAL
ABV.GENERAL.MULTIDIMENSION
ABV.ITERATOR
ABV.MEMBER
ABV.STACK
ABV.TAINTED
ABV.UNICODE.BOUND_MAP
ABV.UNICODE.FAILED_MAP
ABV.UNICODE.NNTS_MAP
ABV.UNICODE.SELF_MAP
ABV.UNKNOWN_SIZE
NNTS.MIGHT
NNTS.MUST
NNTS.TAINTED
SV.STRBO.BOUND_COPY.OVERFLOW
SV.STRBO.BOUND_COPY.UNTERM
SV.STRBO.BOUND_SPRINTF
SV.STRBO.UNBOUND_COPY
SV.STRBO.UNBOUND_SPRINTF
SV.TAINTED.ALLOC_SIZE
SV.TAINTED.CALL.INDEX_ACCESS
SV.TAINTED.CALL.LOOP_BOUND
SV.TAINTED.INDEX_ACCESS
SV.TAINTED.LOOP_BOUND
SV.UNBOUND_STRING_INPUT.CIN
SV.UNBOUND_STRING_INPUT.FUNC

LDRA tool suite
Include Page
LDRA_V
LDRA_V

45 D, 47 S, 489 S, 567 S, 64 X, 66 X, 68 X, 69 X, 70 X, 71 X

Partially implemented

PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

409, 413, 429, 613

Partially supported: conceptually includes all other ARR items which are mapped to their respective guidelines; explicit mappings for ARR00 are present when a situation mentioned in the guideline itself is encountered

Related Vulnerabilities

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

Other Languages

...

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CERT CCTR00

...

...

when to prefer vectors over arraysPrior to 2018-01-12: CERT: Unspecified Relationship
CWE 2.11CWE-119, Improper Restriction of Operations within the Bounds of a Memory BufferPrior to 2018-01-12: CERT:
CWE 2.11CWE-123, Write-what-where ConditionPrior to 2018-01-12: CERT:
CWE 2.11CWE-125, Out-of-bounds ReadPrior to 2018-01-12: CERT:
CWE 2.11CWE-129, Unchecked array indexingPrior to 2018-01-12: CERT:


...

Image Added Image Added

References

Wiki Markup
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.7.5.2, "Array declarators"
\[[MITRE 07|AA. C References#MITRE 07]\] [CWE ID 119|http://cwe.mitre.org/data/definitions/119.html], "Failure to Constrain Operations within the Bounds of an Allocated Memory Buffer," and [CWE ID 129|http://cwe.mitre.org/data/definitions/129.html], "Unchecked Array Indexing"

06. Arrays (ARR)      06. Arrays (ARR)       Image Removed

06. Arrays (ARR)      06. Arrays (ARR)      Image Modified