Functions that take an array as a parameter should also take an additional parameter that indicates the maximum number of elements that can be stored in the array. This additional parameter is required to ensure that the function does not read or write outside the bounds of the array and adversely influence program execution. This additional parameter should be present for each array parameter (in other words, the existence of each array parameter implies the existence of a complementary parameters representing the maximum number of elements in the array).
Note that the word array is used in this recommendation to mean array, string, or any other pointer to a continguous block of memory in which more than one element of a type is (potentially) stored. These terms are all effectively synonomous and represent the same potential for error.
Also note that this recommendation suggests that the parameter accompanying array parameters indicate the maximum number of elements that can be stored in the array and not the maximum size, in bytes, of the array. This is because,
- It does not make sense to think of array sizes in bytes in all cases. For example, it makes little sense to think of an array of integers in its size in bytes.
- If the size in bytes of the array is required it can be derived from the number of elements in the array.
- It is better not to add to the cognitive load of the user of the function and it is probably easier for the user to think of the size of the array in terms of its elements.
In most cases the distinction between number of elements and number of bytes is moot because there is a clear mapping between the two and it is easier to think in terms of number of elements anyway. Unfortunately, this issue can become muddled when working with multibyte strings as the logical entity being manipulated differs from that of type being used to implement it. Here it is important to remind oneself that the type of the array is a character and not a multibyte character. Accordingly, the number of elements in the array is represented as a number of characters.
Noncompliant Code Example
It is not necessary to go beyond the standard C library to find examples that violate this recommendation. This is because the C language often prioritizes performance at the expense of robustness. The following are two examples from §7.21 of the C standard.
char *strncpy(char * restrict s1, const char * restrict s2, size_t n); char *strncat(char * restrict s1, const char * restrict s2, size_t n);
The problem with these functions is twofold. First, there is no indication of the size of the first array, s1. Thus, it is not possible to discern within the function how large s1 is and how many elements may be written into it. Second, while it appears that a size for s2 is supplied this is, in fact, a number of elements to copy. Thus, there is no guarantee that the elements being copied are members of array s2.
Compliant Solution
The above functions could be remedied by adding element count parameters as follows:
char *strncpy(char * restrict s1, size_t s1count, const char * restrict s2, size_t s2count, size_t n); char *strncat(char * restrict s1, size_t s1count, const char * restrict s2, size_t s2count);
Note that for strncpy() it makes sense to maintain the n parameter as the caller may only wish to copy a subset of the total number of elements. For strncat() the n parameter is no longer required.
Risk Assessment
Failure to do so can result in type errors in the program.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
API02-C |
low |
probable |
high |
P6 |
L2 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.