c-为什么在calloc之后调用memset



我研究了一些库的代码,注意到对calloc的调用后面跟着calloc分配的块的memset。我发现这个问题对callocmalloc+memset之间的差异有着相当全面的回答,并且在分配存储之前调用memset

为什么malloc+memset比calloc慢?

我仍然不能理解的是为什么人们会这么做。这种操作的好处是什么?

上面提到的库中的代码示例:

light_pcapng_file_info *light_create_default_file_info()
{
light_pcapng_file_info *default_file_info = calloc(1, sizeof(light_pcapng_file_info));
memset(default_file_info, 0, sizeof(light_pcapng_file_info));
default_file_info->major_version = 1;
return default_file_info;
}

分配结构的代码(每个数组包含32个元素):

typedef struct _light_pcapng_file_info {
uint16_t major_version;
uint16_t minor_version;
char *file_comment;
size_t file_comment_size;
char *hardware_desc;
size_t hardware_desc_size;
char *os_desc;
size_t os_desc_size;
char *user_app_desc;
size_t user_app_desc_size;
size_t interface_block_count;
uint16_t link_types[MAX_SUPPORTED_INTERFACE_BLOCKS];
double timestamp_resolution[MAX_SUPPORTED_INTERFACE_BLOCKS];
} light_pcapng_file_info;

编辑:

除了公认的答案外,我还想提供一些同事向我指出的信息。glibc中有一个错误,有时会阻止calloc清空内存。链接如下:https://bugzilla.redhat.com/show_bug.cgi?id=1293976

如果链接被移动,实际错误报告文本:

glibc:calloc()返回非零内存

问题描述:

在Facebook上,我们有一个应用程序,从glibc-12.12-1.149.el6.x86_64到glibc-12.2-1.163.el6.x86_64时,它开始奇怪地挂起并崩溃。发现这个补丁

glibc-h1066724.补丁

介绍了问题。

您向_int_malloc()添加了以下位

/* There are no usable arenas.  Fall back to sysmalloc to get a chunk from
mmap.  */
if (__glibc_unlikely (av == NULL))
{
void *p = sYSMALLOc (nb, av);
if (p != NULL)
alloc_perturb (p, bytes);
return p;
}

但这不好,alloc_perturb无条件地将前面的字节memset为0xf,而不像上游那样,它检查是否设置了扰动字节。这需要更改为

if (p != NULL && && __builtin_expect(perturb_byte, 0))
alloc_perturb (p, bytes);
return p;

我所附的补丁为我修复了这个问题。

竞技场上的任何类型的锁争用都会导致我们回到mmap()的新区块,这一事实加剧了这个问题。这是因为我们检查我们检查的未受控制的竞技场是否腐败,如果是,我们循环通过,如果我们循环到一开始,我们知道我们什么都没发现。除非我们最初的竞技场实际上没有损坏,否则我们仍然会返回NULL,所以我们更频繁地使用mmap(),这确实会使事情变得不稳定。

请尽快解决这个问题,我甚至认为这可能是一个安全问题。

调用memset()可确保操作系统实际执行虚拟内存映射。正如您链接的问题的答案中所指出的,calloc()可以进行优化,以便推迟实际的内存映射。

应用程序可能有理由推迟虚拟内存映射的实际创建,例如使用缓冲区从非常高速的设备读取,尽管在使用memset()将内存清零的情况下,使用calloc()而不是malloc()似乎是多余的。

没有人是完美的,仅此而已。是的,memsetcalloc之后归零是奢侈的。如果你想要一个明确的memset来保证你拥有你所要求的内存,那么它应该跟在malloc后面。

新代码每1000行大约有20个错误,概率定律意味着并非所有错误都被清除了。此外,这并不是一个真正的错误,因为没有不良行为可以观察到。

我会称之为bug,因为它正在做毫无意义的工作,calloc()被指定返回已经清除的内存,为什么要再次清除它呢?当有人从malloc()切换时,可能是一次失败的重构。

如果代码是开源的和/或在您可以访问的存储库中,我会检查这些行的提交历史记录,看看发生了什么。幸运的是,有一条提交消息告诉动机。。。

相关内容

  • 没有找到相关文章

最新更新