The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. However, using the sizeof operator to determine the size of arrays is error prone.
In this non-compliant 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 twelve {{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 {{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. |
void clear(int array[]) {
size_t i;
for (i = 0; i < sizeof(array) / sizeof(array[0]); ++i) {
array[i] = 0;
}
}
void dowork(void) {
int dis[12];
clear(dis);
/* ... */
}
|
The footnote in Section 6.5.3.4 of the C Standard \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] explains: |
When applied to a parameter declared to have array or function type, the
sizeofoperator yields the size of the adjusted (pointer) type . . . .
This applies to all array parameters, even if the parameter declaration contains an index.
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.
void clear(int array[], size_t size) {
size_t i;
for (i = 0; i < size; i++) {
array[i] = 0;
}
}
void dowork(void) {
int dis[12];
clear(dis, sizeof(dis) / sizeof(dis[0]));
/* ... */
}
|
This {{sizeof(array) / sizeof(array\[0\])}} idiom will succeed provided the original definition of {{array}} is visible. |
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 |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
ARR01-A |
high |
probable |
low |
P18 |
L1 |
The LDRA tool suite V 7.6.0 can detect violations of this recommendation.
Splint Version 3.1.1 can detect violations of this recommendation.
Compass/ROSE can detect violations of the recommendation, but it cannot distinguish between incomplete array declarations and pointer declarations.
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.7.5.2, "Array declarators" \[[Drepper 06|AA. C References#Drepper 06]\] Section 2.1.1, "Respecting Memory Bounds" |
ARR00-A. Understand how arrays work 06. Arrays (ARR) ARR02-A. Explicitly specify array bounds, even if implicitly defined by an initializer