提问人:bryc_wall 提问时间:9/29/2023 更新时间:9/29/2023 访问量:37
重新分配以前分配的指向 SIZE_MAX 的指针不会设置 ENOMEM,但重新分配 NULL 有效吗?
Reallocating a previously allocated pointer to SIZE_MAX doesn't set ENOMEM, but reallocating NULL works?
问:
问题:
我正在努力重写一些 malloc 函数(、、和),我决定实现一些单元测试,希望能让自己的事情变得更容易一些(而且这似乎是一个很好的做法)。malloc
calloc
realloc
free
在进行设置时,我使用标准的“分配”来确保测试正常运行。不幸的是,我在以下测试中遇到了问题:
#include "unity.h"
#include <stdlib.h>
#include <errno.h>
#include "nmalloc.h"
void realloc_overflow(void)
{
// Reset ERRNO
errno = 0;
// Verify allocating SIZE_MAX sets ENOMEM when reallocating NULL
TEST_ASSERT_EQUAL_PTR(NULL, my_realloc(NULL, SIZE_MAX)); // <-- Sets ENOMEM
TEST_ASSERT_ERRNO(ENOMEM);
// Allocate 112 bytes
void* ptr = my_malloc(ALLOC_LEN_112U);
TEST_ASSERT_TRUE(ptr != NULL);
// Reset ERRNO
errno = 0;
// Verify allocating SIZE_MAX sets ENOMEM when reallocating a valid pointer
// ! This doesn't set errno to ENOMEM on my system? However (SIZE_MAX + 1) does?
TEST_ASSERT_EQUAL_PTR(NULL, my_realloc(ptr, SIZE_MAX));
TEST_ASSERT_ERRNO(ENOMEM);
my_free(ptr);
}
这给出了一个意想不到的输出:
test/Test-nmalloc.c:326:realloc_overflow:FAIL: Expected 12 Was 0
奇怪的是,使用显示了设置的预期行为?realloc(valid_ptr, SIZE_MAX + 1)
errno = ENOMEM
注意:如果它变得重要,我正在 M1 Mac 上测试所有这些
尝试解决方案:
我做了一个最小的可行例子:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "nmalloc.h"
#define ALLOC_LEN_112U 112U
int main(void)
{
errno = 0;
// TEST_ASSERT_EQUAL_PTR(NULL, my_realloc(NULL, SIZE_MAX));
if (NULL == realloc(NULL, SIZE_MAX))
printf("PASS: null_ptr is NULL.\n");
else
{
printf("ERR: null_ptr is not NULL!\n");
return 1;
}
// TEST_ASSERT_ERRNO(ENOMEM);
if (errno == ENOMEM)
printf("PASS: errno is ENOMEM.\n");
else
{
printf("ERR: errno is not NULL!\n");
return 1;
}
void *valid_ptr = malloc(ALLOC_LEN_112U);
// TEST_ASSERT_TRUE(ptr != NULL);
if (valid_ptr == NULL)
{
printf("ERR: valid_ptr is NULL!\n");
return 1;
}
else
printf("PASS: valid_ptr is not NULL.\n");
errno = 0;
// TEST_ASSERT_EQUAL_PTR(NULL, realloc(ptr, SIZE_MAX));
if (NULL == realloc(valid_ptr, SIZE_MAX))
printf("PASS: invalid_ptr is NULL.\n");
else
{
printf("ERR: invalid_ptr is not NULL!\n");
return 1;
}
// TEST_ASSERT_ERRNO(ENOMEM);
if (errno == ENOMEM)
printf("PASS: errno is ENOMEM.\n");
else
{
printf("ERR: errno is not NULL!\n");
return 1;
}
free(valid_ptr);
printf("Success!");
}
这给出了正确的预期输出???
[user@machine ~/test] % clang alloc-test.c nmalloc.o -I./lib -o alloc-test.o && ./alloc-test.o
PASS: null_ptr is NULL.
PASS: errno is ENOMEM.
PASS: valid_ptr is not NULL.
PASS: invalid_ptr is NULL.
PASS: errno is ENOMEM.
Success!
[user@machine ~/test] %
即使包含库(即添加一个,而不仅仅是将其添加到 clang),一切似乎都正常。所以在这一点上,我不完全确定这里发生了什么,所以一些见解将不胜感激。也许我只是错过了一些微妙(或明显)的东西?jemalloc
#include <...>
谢谢!:)
答:
0赞
0___________
9/29/2023
#1
SIZE_MAX 不是可以分配的最大内存大小,只能分配 可以保存的最大值。 和 IS 实现定义的行为
size_t
(SIZE_MAX + 1) == 0
realloc
SIZE_MAX
远远超过Linux 64中虚拟内存的128TB。所以家庭功能会失败。malloc
奇怪的是,使用 realloc(valid_ptr, SIZE_MAX + 1) 显示 设置 errno = ENOMEM 的预期行为?
(MAX_SIZE + 1)
为零,并且标准未指定本例中的行为。
评论
0赞
Barmar
9/29/2023
Realloc 只需要触摸与旧分配大小相对应的新内存部分,因为它必须复制它。
评论