The sizeof
operator yields the size (in bytes) of its operand, which can be an expression or the parenthesized name of a type. However, using the sizeof
operator to determine the size of arrays is error prone.
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.
void clear(int array[]) { for (size_t 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] explains this:
When applied to a parameter declared to have array or function type, the
sizeof
operator yields the size of the adjusted (pointer) type . . . .
This applies to all array parameters.
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.
void clear(int array[], size_t len) { for (size_t i = 0; i < len; 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.
Noncompliant Code Example
In this noncompliant code example, the sizeof a
does not equal 100 * sizeof(int)
. This is because the sizeof
operator, when applied to a parameter declared to have array or function type, yields the size of the adjusted (pointer) type, even if the parameter declaration specifies a length.
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)
.
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 |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
ARR01-C |
high |
probable |
low |
P18 |
L1 |
Automated Detection
Tool |
Version |
Checker |
Description |
---|---|---|---|
Splint |
3.1.1 |
|
|
Compass/ROSE |
|
|
can detect violations of the recommendation, but it cannot distinguish between incomplete array declarations and pointer declarations |
9.7.1 | 401 S |
Partially Implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard: ARR01-CPP. Do not apply the sizeof operator to a pointer when taking the size of an array
ISO/IEC 9899:1999 Section 6.7.5.2, "Array declarators"
MITRE CWE: CWE-467, "Use of sizeof() on a Pointer Type"
Bibliography
[Drepper 2006] Section 2.1.1, "Respecting Memory Bounds"
06. Arrays (ARR) ARR02-C. Explicitly specify array bounds, even if implicitly defined by an initializer