...
Any variable that is used to represent the size of an object including integer values used as sizes, indices, loop counters, and lengths should be declared as rsize_t
if available, otherwise size_t
.
...
Non-Compliant Code Example
In this non-compliant code example, the dynamically allocated buffer referenced by p
overflows for values of n > INT_MAX
.
Code Block | ||
---|---|---|
| ||
char *copy(size_t n, const char *str) {
int i;
char *p = (char *)malloc(n);
if (p == NULL) {
/* Handle malloc failure */
}
for ( i = 0; i < n; ++i ) {
p[i] = *str++;
}
return p;
}
char *p = copy(9, "hi there");
|
Wiki Markup |
---|
The {{size_t}} type is typically represented by the same number of bits as {{int}}, that is, {{sizeof(size_t) == sizeof(int))}}. In this case, {{n}} might be greater than {{INT_MAX}}. The loop, however, will executes {{n}} times because the comparison {{i < n}} is an unsigned comparison. Once {{i > INT_MAX}}, {{i}} takes on negative values starting with ({{INT_MIN}}). Consequently, the memory locations referenced by {{p\[i\]}} precede the memory referenced by {{p}} and a write-outside-array bounds occurs. |
Wiki Markup |
---|
If {{size_t}} is represented by a greater number of bits than {{int}}, {{that is sizeof(size_t) > sizeof(int)}}, the same behavior occurs for values of {{n <= UINT_MAX}}. For values of {{n > UINT_MAX}} all of memory within {{\[INT_MIN, INT_MAX\]}} from the beginning of the output buffer are overwritten in an infinite loop. This is because the expression {{\++i}} will wrap around to zero before the condition {{i < n}} ever evaluates to false. |
Note that in a preemptive multithreaded program, only one thread is in the infinite loop, so it is still significant that out-of-bounds memory is changed.
Compliant Solution
Declaring i
to be of type rsize_t
eliminates the possible integer overflow condition (in this example). Also, the argument n
is changed to be of type rsize_t
to document additional validation in the form of a check against RSIZE_MAX
.
Code Block | ||
---|---|---|
| ||
char *copy(rsize_t n, const char *str) {
rsize_t i;
char *p;
if (n > RSIZE_MAX) {
/* Handle unreasonable object size error */
}
p = (char *)malloc(n);
if (p == NULL) {
/* Handle malloc failure */
}
for ( i = 0; i < n; ++i ) {
p[i] = *str++;
}
return p;
}
char *p = copy(9, "hi there");
|
...
Include Page | ||||
---|---|---|---|---|
|
...