我正在重写一些 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] %
即使包含
jemalloc
库(即添加 #include <...>
,而不仅仅是将其添加到 clang),一切似乎都正常。所以在这一点上,我不完全确定这里发生了什么,所以一些见解将非常感激。也许我只是错过了一些微妙(或明显)的东西?
谢谢! :)
SIZE_MAX 不是可分配的最大内存大小,仅是
size_t
可以容纳的最大值。 (SIZE_MAX + 1) == 0
并且 realloc
的行为是由 实现定义的
SIZE_MAX
远远超过了Linux 64中的128TB虚拟内存。所以malloc
家庭功能将会失败。