如果我使用大小为 NaN 的 malloc() 会发生什么?

问题描述 投票:0回答:2

我目前正在搞乱内存管理,但是,如果我使用大小为 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 malloc nan
2个回答
2
投票

当调用具有原型的函数时,每个实参都会像通过赋值一样转换为相应参数的类型,根据 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,因此该行为因省略而未定义。


0
投票

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
处的内存,但删除该调用并不能解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.