One of the problems with arrays is determining the size. The sizeof operator yields the size (in bytes) of its operand, which may can be an expression or the parenthesized name of a type.
Non-compliant Code Example 1
This piece of code incorrectly uses However, using the sizeof operator . When applied to a pointer, the sizeof operator returns the size of the pointer, not the size of the block of space the pointer refers to. As a result the call to malloc will return a pointer to a block of memory equal in size to the size of a pointer (commonly 4 bytes). When the strcpy is called a heap buffer overflow will occur.
| Code Block |
|---|
char *src = "hello, world";
char *dest = malloc(sizeof(src));
strcpy(dest, src);
|
Compliant Solution 1
Fixing this issue requires the programmer to recognize and understand how sizeof works. In this case if, changing the type of src to a character array will correct the problem
| Code Block |
|---|
char src[] = "hello, world";
char *dest = malloc(sizeof(src));
strcpy(dest, src);
|
Non-compliant Code Example 2
The sizeof operator can be used to compute the number of elements in an array as follows: sizeof (dis) / sizeof (dis0). The sizeof operator can also be used to calculate the size of variable length arrays. In the case of a variable length array, the operand is evaluated at runtime. Extreme care must be taken when using this particular programming idiom, however.
to determine the size of arrays is error prone.
The sizeof operator is often used in determining how much memory to allocate via malloc(). However using an incorrect size is a violation of MEM35-C. Allocate sufficient memory for an object.
Noncompliant Code Example
In this noncompliant code example, the function clear() zeros the elements in an array. The function has one parameter declared as int array[] and is passed a static array consisting of 12 int as the argument. The function clear() uses the idiom sizeof(array) / sizeof(array[0]) to determine the number of elements in the array. However, array has a pointer type because it is a parameter. As a result, sizeof(array) is equal to the sizeof(int *). For example, on an architecture (such as IA-32) where the sizeof(int) == 4 and the sizeof(int *) == 4, the expression sizeof(array) / sizeof(array[0]) evaluates to 1, regardless of the length of the array passed, leaving the rest of the array unaffected.
| Code Block | ||||
|---|---|---|---|---|
| ||||
void clear(int array[]) {
for (size_t | ||||
| Code Block | ||||
void f(int a[]) { int i; for (i = 0; i < sizeof (aarray) / sizeof (aarray[0]); i++i) { aarray[i] = 210; } } intvoid maindowork(void) { int dis[12]; fclear(dis); /* ... */ } |
In the following example sizeof (a) / sizeof (a0) evaluates to 1 because int a[] is equivalent to int *a in the function declaration. This allows f() to be passed an array of arbitrary length.
Compliant Solution
This problem can be fixed by passing the size as a separate argument, as shown in the following example:
Footnote 103 in subclause 6.5.3.4 of the C Standard [ISO/IEC 9899:2011] applies to all array parameters:
When applied to a parameter declared to have array or function type, the
sizeofoperator yields the size of the adjusted (pointer) type.
Compliant Solution
In this compliant solution, the size of the array is determined inside the block in which it is declared and passed as an argument to the function:
| Code Block | ||||
|---|---|---|---|---|
| ||||
void clear(int array[], size_t len) {
for (size_t | ||||
| Code Block | ||||
void g(int a[], int size) { int i; for (i = 0; i < sizelen; i++) { a array[i] = 210; } } g void dowork(void) { int dis[12]; clear(dis, sizeof (dis) / sizeof (dis[0])); |
Care must be taken to ensure that the size is valid for the array. If these parameters can be manipulated by an attacker, this function will almost always result in an exploitable vulnerability.
Compliant Code Example 2
In general, correcting issues regarding improper use of the sizeof operator requires that the programmer have a solid understanding of how sizeof works. Consider the following data types and variables:
| Code Block |
|---|
struct test_struct {
char c1,c2;
int *integer_ptr;
};
char array[10];
char * pointer = malloc(10);
char character;
struct test_struct structure;
struct test_struct struct_array[10];
|
The following are the implementation specific results of using the sizeof operator on those data types:
...
/* ... */
}
|
This sizeof(array) / sizeof(array[0]) idiom will succeed provided the original definition of array is visible.
Noncompliant Code Example
In this noncompliant code example, sizeof(a) does not equal 100 * sizeof(int), because the sizeof operator, when applied to a parameter declared to have array type, yields the size of the adjusted (pointer) type even if the parameter declaration specifies a length:
| Code Block | ||||
|---|---|---|---|---|
| ||||
enum {ARR_LEN = 100};
void clear(int a[ARR_LEN]) {
memset(a, 0, sizeof(a)); /* Error */
}
int main(void) {
int b[ARR_LEN];
clear(b);
assert(b[ARR_LEN / 2]==0); /* May fail */
return 0;
}
|
Compliant Solution
In this compliant solution, the size is specified using the expression len * sizeof(int):
| Code Block | ||||
|---|---|---|---|---|
| ||||
enum {ARR_LEN = 100};
void clear(int a[], size_t len) {
memset(a, 0, len * sizeof(int));
}
int main(void) {
int b[ARR_LEN];
clear(b, ARR_LEN);
assert(b[ARR_LEN / 2]==0); /* Cannot fail */
return 0;
}
|
Risk Assessment
Incorrectly using the sizeof operator to determine the size of an array can result in a buffer overflow, allowing the execution of arbitrary code.
Recommendation | Severity | Likelihood | Detectable | Repairable | Priority | Level |
|---|---|---|---|---|---|---|
ARR01-C | High | Probable | No | Yes | P12 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Astrée |
| sizeof-array-parameter | Fully checked | ||||||
| Axivion Bauhaus Suite |
| CertC-ARR01 | Fully implemented | ||||||
| CodeSonar |
| LANG.TYPE.SAP | sizeof Array Parameter | ||||||
| Compass/ROSE | Can detect violations of the recommendation but cannot distinguish between incomplete array declarations and pointer declarations | ||||||||
| Helix QAC |
| C1321 | |||||||
| Klocwork |
| CWARN.MEMSET.SIZEOF.PTR | Fully implemented | ||||||
| LDRA tool suite |
| 401 S | Fully implemented | ||||||
| Parasoft C/C++test |
| CERT_C-ARR01-a | Do not call 'sizeof' on a pointer type | ||||||
| PC-lint Plus |
| 682, 882 | Fully supported | ||||||
| Polyspace Bug Finder |
| Checks for:
Rec, fully covered. | |||||||
| Splint |
| ||||||||
| PVS-Studio |
| V511, V512, V514, V568, V579, V604, V697, V1086 | |||||||
| RuleChecker |
| sizeof-array-parameter | Fully checked |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Key here (explains table format and definitions)
Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| CERT C | CTR01-CPP. Do not apply the sizeof operator to a pointer when taking the size of an array | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CWE 2.11 | CWE-467, Use of sizeof() on a pointer type | Prior to 2018-01-12: CERT: |
| ISO/IEC TS 17961 | Taking the size of a pointer to determine the size of the pointed-to type [sizeofptr] | Prior to 2018-01-12: CERT: Unspecified Relationship |
| MITRE CWE | CWE-569 | Prior to 2018-01-12: |
| MITRE CWE | CWE-783 | Prior to 2018-01-12: |
Bibliography
| [Drepper 2006] | Section 2.1.1, "Respecting Memory Bounds" |
| [ISO/IEC 9899:2011] | Subclause 6.5.3.4, "The sizeof and _Alignof Operators" |
...
...