为什么memset在calloc之后调用?

too*_*zzy 4 c malloc memset calloc

我已经研究了一些库的代码,并注意到那里的调用calloc后面跟着memset分配的块calloc.我发现这个问题有一个非常全面的答案,关于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;
}
Run Code Online (Sandbox Code Playgroud)

分配结构的代码(每个数组包含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;
Run Code Online (Sandbox Code Playgroud)

编辑:

除了接受的答案,我想提供一些我的同事指出的信息.glibc中有一个错误,有时会阻止calloc将内存清零.这是链接:https: //bugzilla.redhat.com/show_bug.cgi?id = 1293976

案例链接移动时的实际错误报告文本:

glibc:calloc()返回非零内存

问题描述:

在Facebook,我们有一个应用程序,当从glibc-2.12-1.149.el6.x86_64转到glibc-2.12-1.163.el6.x86_64时,它开始悬挂和崩溃.原来这个补丁

的glibc-rh1066724.patch

介绍了这个问题.

您将以下位添加到_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;
    }
Run Code Online (Sandbox Code Playgroud)

但这不行,alloc_perturb无条件地将前端字节memset设置为0xf,与上游不同,它检查是否设置了perturb_byte.这需要改为

if (p != NULL && && __builtin_expect(perturb_byte, 0))
   alloc_perturb (p, bytes);
return p;
Run Code Online (Sandbox Code Playgroud)

我附上的补丁修复了我的问题.

这个问题因为竞技场上的任何类型的锁争用导致我们回到mmap()的新块而加剧了这个问题.这是因为我们检查我们检查的无竞争竞技场是否已损坏,如果是我们循环,如果我们循环到开头,我们知道我们没有找到任何东西.除非我们的初始竞技场实际上没有损坏我们仍然会返回NULL,所以我们更经常地回到这个mmap()的东西,这真的让事情变得不稳定.

请尽快修复此问题,我甚至会将其称为可能的安全问题.

And*_*nle 7

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

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

  • @Lundin它是不是每页需要触摸的一个存储单元*?在OP的帖子中的示例中,它可能是单个页面(甚至是页面的一部分),但如果内存跨越多个页面并且页面大小未知,那么`memset`调用可能更简单. (2认同)
  • 无论如何,如果目的是强制分配,我肯定会期待一些解释这是目的的评论. (2认同)
  • 注意``gcc 8.2.1`在`calloc()`之后很高兴地将`memset()`优化为零,所以这种预先破坏地址的尝试将会破坏一个理智的编译器*无论如何*. (2认同)
  • @Lundin 但是“代码是由某个菜鸟编写的。” ;-) (2认同)