C语言 如何避免在realloc中溢出?



可以使用calloc(x, y)安全地分配xC中大小为y的元素,calloc()将负责乘法x*y

但是realloc()例如仅将新大小作为参数,我想知道如何使用realloc()安全地重新分配x*y字节。

如果x*y不适合size_t怎么办?calloc()如何处理这个问题?

size_t是无符号类型,最大值size_t是可以用reallocmalloc分配的对象的绝对最大大小;这在宏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必须返回NULL,因此calloc很可能有一个类似于上面的检查。

简短的回答是你不能安全地做到这一点。 您最多可以做的是限制您尝试分配的内存量,使其不超过SIZE_MAX

SIZE_MAXsizeof运算符可以产生的最大值。

C 语言中的每种数据类型都必须有一个可以使用sizeof计算的大小,包括数组,以及使用malloc()calloc()realloc()分配的任何连续内存块。

如果x*y在数学上大于SIZE_MAX,那么无论如何都不可能分配该内存量。 即使底层系统支持这一点,C 程序也无法完全使用该内存块。

还有一个问题是,计算x*y(假设xysize_t类型)将使用模算术,因此实际上会在数学上给出等同于(x*y)%(SIZE_MAX + 1)的结果。

如果 x*y 不适合size_t怎么办?calloc()如何处理这个问题?

realloc()malloc()受到限制,因为传递给它们的大小参数仅限于SIZE_MAXcalloc()不是这样

不需要兼容的 C 实现来限制calloc()仅分配SIZE_MAX的内存。 以下方法可能有效。 单个类型的最大大小可以SIZE_MAX数组大小可以大SIZE_MAXSIZE_MAX-1"字节",但下面的iptr不是数组,而是指针。

// Assume sizeof(double) == 8
double *iptr = calloc(SIZE_MAX, sizeof *iptr);

重新分配如此大的指针是有问题的,因为它需要使用另一个调用来calloc()


如何避免realloc溢出?

OP 的问题不在于realloc()可以处理什么,而在于代码如何计算传递给它的值可能会溢出。

要确保无符号类型(如size_t)不会溢出乘法,请执行以下操作:

if (b && a > SIZE_MAX/b) Handle_Overflow();
prod = a*b;
size_t

是无符号类型。

对于无符号类型,溢出行为是确定性的,如C11中所述

[....] 因为不能用生成的无符号整数类型表示的结果是 降模 大于最大值 1 的数字 由结果类型表示。

因此,只要确保生成要存储在变量类型中的值的操作不会在过程中溢出size_t,将该变量传递给realloc()就没有影响。最多,realloc()将无法分配该内存。

如果x * y溢出size_t,realloc将尝试分配溢出的值:

bytes = (x * y) % 2^(sizeof(size_t) * 8)

因此,realloc将"看到"bytes字节数。它不照顾任何事情。

相关内容

  • 没有找到相关文章

最新更新