如何避免 realloc 溢出?
How to avoid overflow in realloc?
可以使用 calloc(x, y)
在 C 中安全地分配 x
个大小为 y
的元素,而 calloc()
将负责乘法 x*y
。
但是 realloc()
例如仅将新大小作为参数,我想知道如何使用 realloc()
.
安全地重新分配 x*y
字节
如果 x*y
不适合 size_t
怎么办? calloc()
如何处理这个问题?
size_t
是无符号类型。
对于无符号类型,溢出行为是确定性的,如 C11
中所述
[....] because a result that cannot be represented by the resulting unsigned integer type is
reduced modulo the number that is one greater than the largest value that can be
represented by the resulting type.
因此,只要您确保生成要存储在变量类型 size_t
中的值的操作不会在过程中溢出,将该变量传递给 realloc()
就没有影响.最多,realloc()
将无法分配该内存。
如果 x * y
溢出 size_t
,realloc 将尝试分配溢出的值:
bytes = (x * y) % 2^(sizeof(size_t) * 8)
因此 realloc
将 "see" bytes
字节数。它不关心任何事情。
size_t
是无符号类型,size_t
的最大值是realloc
或malloc
可以分配的对象的绝对最大大小;这在宏 SIZE_MAX
中可用。在 32 位个人计算机上,size_t
通常是 32 位; 64 位计算机上的 64 位。应该够了。
为保证item_size * n_items
的计算不溢出,可以将SIZE_MAX
除以item_size
,并保证结果值大于等于n_items
:
size_t max_items = SIZE_MAX / item_size;
if (max_items < n_items) {
// an overflow would occur
}
else {
// it is ok
}
calloc
必须 return NULL
如果分配没有成功,所以 calloc
很可能有一个类似于上面的检查。
简短的回答是你不能安全地做到这一点。您最多可以做的是限制您尝试分配的内存量,使其不超过 SIZE_MAX
.
SIZE_MAX
是 sizeof
运算符可以产生的最大值。
C 中的每个数据类型都必须具有可以使用 sizeof
计算的大小,包括数组,以及使用 malloc()
、calloc()
或 [分配的任何连续内存块=16=].
如果 x*y
在数学上大于 SIZE_MAX
,则不可能以任何方式分配该数量的内存。即使底层系统支持,C 程序也无法完全使用该内存块。
还有一个问题是计算 x*y
(假设 x
和 y
是 size_t
类型)将使用模运算,因此实际上会给出结果数学上等同于 (x*y)%(SIZE_MAX + 1)
.
What if x*y doesn't fit in size_t? How does calloc()
handle this?
realloc()
和 malloc()
的限制在于传递给它们的大小参数被限制为 SIZE_MAX
。 calloc()
不是这样
兼容的 C 实现 不需要 来限制 calloc()
仅分配 SIZE_MAX
的内存。以下可能有效。单个类型的最大大小可以为 SIZE_MAX
,而 array 的大小可以达到 SIZE_MAX
SIZE_MAX-1"bytes",但下面的iptr
不是数组,而是指针。
// Assume sizeof(double) == 8
double *iptr = calloc(SIZE_MAX, sizeof *iptr);
重新分配如此大的指针是有问题的,因为它需要再次调用 calloc()
How to avoid overflow in realloc
?
OP 的问题与其说是 realloc()
可以处理的问题,不如说是代码如何计算传递给它的值可能会溢出。
为了确保 unsigned 类型,如 size_t
,不会溢出乘法:
if (b && a > SIZE_MAX/b) Handle_Overflow();
prod = a*b;
可以使用 calloc(x, y)
在 C 中安全地分配 x
个大小为 y
的元素,而 calloc()
将负责乘法 x*y
。
但是 realloc()
例如仅将新大小作为参数,我想知道如何使用 realloc()
.
x*y
字节
如果 x*y
不适合 size_t
怎么办? calloc()
如何处理这个问题?
size_t
是无符号类型。
对于无符号类型,溢出行为是确定性的,如 C11
[....] because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.
因此,只要您确保生成要存储在变量类型 size_t
中的值的操作不会在过程中溢出,将该变量传递给 realloc()
就没有影响.最多,realloc()
将无法分配该内存。
如果 x * y
溢出 size_t
,realloc 将尝试分配溢出的值:
bytes = (x * y) % 2^(sizeof(size_t) * 8)
因此 realloc
将 "see" bytes
字节数。它不关心任何事情。
size_t
是无符号类型,size_t
的最大值是realloc
或malloc
可以分配的对象的绝对最大大小;这在宏 SIZE_MAX
中可用。在 32 位个人计算机上,size_t
通常是 32 位; 64 位计算机上的 64 位。应该够了。
为保证item_size * n_items
的计算不溢出,可以将SIZE_MAX
除以item_size
,并保证结果值大于等于n_items
:
size_t max_items = SIZE_MAX / item_size;
if (max_items < n_items) {
// an overflow would occur
}
else {
// it is ok
}
calloc
必须 return NULL
如果分配没有成功,所以 calloc
很可能有一个类似于上面的检查。
简短的回答是你不能安全地做到这一点。您最多可以做的是限制您尝试分配的内存量,使其不超过 SIZE_MAX
.
SIZE_MAX
是 sizeof
运算符可以产生的最大值。
C 中的每个数据类型都必须具有可以使用 sizeof
计算的大小,包括数组,以及使用 malloc()
、calloc()
或 [分配的任何连续内存块=16=].
如果 x*y
在数学上大于 SIZE_MAX
,则不可能以任何方式分配该数量的内存。即使底层系统支持,C 程序也无法完全使用该内存块。
还有一个问题是计算 x*y
(假设 x
和 y
是 size_t
类型)将使用模运算,因此实际上会给出结果数学上等同于 (x*y)%(SIZE_MAX + 1)
.
What if x*y doesn't fit in size_t? How does
calloc()
handle this?
realloc()
和 malloc()
的限制在于传递给它们的大小参数被限制为 SIZE_MAX
。 calloc()
兼容的 C 实现 不需要 来限制 calloc()
仅分配 SIZE_MAX
的内存。以下可能有效。单个类型的最大大小可以为 SIZE_MAX
,而 array 的大小可以达到 SIZE_MAX
SIZE_MAX-1"bytes",但下面的iptr
不是数组,而是指针。
// Assume sizeof(double) == 8
double *iptr = calloc(SIZE_MAX, sizeof *iptr);
重新分配如此大的指针是有问题的,因为它需要再次调用 calloc()
How to avoid overflow in
realloc
?
OP 的问题与其说是 realloc()
可以处理的问题,不如说是代码如何计算传递给它的值可能会溢出。
为了确保 unsigned 类型,如 size_t
,不会溢出乘法:
if (b && a > SIZE_MAX/b) Handle_Overflow();
prod = a*b;