我目前正在搞乱内存管理,但是,如果我使用大小为 NaN 的 malloc() 会怎么样?我将展示我正在谈论的代码:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#define fam 100
#define pnm 1000
#define pcb 252
int main() {
char *ptr = malloc(nan); <--- THIS MALLOC HERE
sleep(1);
free(ptr);
strncpy(ptr, "amd", fam);
char *ptr2 = malloc(pcb);
memcpy(ptr2, ptr, 45 << -1);
}
我运行了这段代码,没有任何编译器错误。我认为 malloc(nan) 不会执行任何操作,但我不知道这是否属实。这是一个漏洞吗?
当调用具有原型的函数时,每个实参都会像通过赋值一样转换为相应参数的类型,根据 C 2018 6.5.2.2 7。
malloc
使用类型为 size_t
的参数进行声明,即无符号整数类型。
如果调用为
malloc(nan)
,则 nan
指定在 <math.h>
中声明的函数,并且根据 6.3.2.1 4,它会自动转换为指向该函数的指针。 对于将指针类型分配给其他整数类型比 _Bool
,编译器必须生成诊断消息,因为它违反了 6.5.16.1 1 中的约束。假设编译器继续进行转换,C 标准中没有指定从函数指针到整数类型的转换(它将在 6.3.2.3 中),因此该行为不是由 C 标准定义的。
如果调用是
malloc(NAN)
,我们会将 double
值转换为无符号整数类型。这是在6.3.1.4 1中规定的。对于数值,它规定丢弃小数部分,并且“如果整数部分的值不能用整数类型表示,则行为未定义”。我们可以用两种方式解释这一点:要么 NaN 的整数部分的值不能用整数类型表示,因为没有整数部分,因此该行为未通过显式语句定义,或者本段没有指定 NaN 会发生什么NaN,因此该行为因省略而未定义。
TL/DR - 尝试分配
NaN
字节会导致未定义的行为。您的代码可能会彻底崩溃,它可能会按预期工作(尽管我不知道您会期望什么),或者介于两者之间。别这样做。
我运行了这段代码,没有任何编译器错误。
我不相信你:
% gcc -o bad_malloc bad_malloc.c -lm
bad_malloc.c:12:24: warning: incompatible pointer to integer conversion passing 'double (const char *)' to parameter of type 'unsigned long' [-Wint-conversion]
char *ptr = malloc(nan);
^~~
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/malloc/_malloc.h:45:21: note: passing argument to parameter '__size' here
void *malloc(size_t __size) __result_use_check __alloc_size(1) _MALLOC_TYPED(malloc_type_malloc, 1);
^
bad_malloc.c:18:26: warning: shift count is negative [-Wshift-count-negative]
memcpy(ptr2, ptr, 45 << -1);
^ ~~
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/secure/_string.h:63:33: note: expanded from macro 'memcpy'
__builtin___memcpy_chk (dest, __VA_ARGS__, __darwin_obsz0 (dest))
^~~~~~~~~~~
您必须已经得到某种诊断,因为您所做的事情违反了约束。
malloc
需要一个size_t
类型的参数,但是您将一个指针传递给nan
函数,而不是一个NaN
值,其类型为double (*)(const char *)
。这些类型不兼容,并且尝试将一种类型转换为另一种类型,就像通过赋值一样必须生成某种诊断。
现在,由于我没有告诉
gcc
将警告视为错误(我通常这样做,你也应该这么做),它确实生成了一个可执行文件。运行它给我这个:
% ./bad_malloc
zsh: segmentation fault ./bad_malloc
在运行时,将任何函数指针作为参数传递给
malloc
的行为是未定义的;在这种特殊情况下,malloc
返回了非NULL
值0x280000000
(这在我的系统上看起来不像是有效的堆地址)。
您遇到了逻辑错误,在尝试写入之前,您
free
位于ptr
处的内存,但删除该调用并不能解决问题。