Почему memset вызывается после calloc? - PullRequest
0 голосов
/ 07 февраля 2019

Я исследовал код какой-то библиотеки и заметил, что после вызовов calloc следует memset для блока, выделенного calloc.Я нашел этот вопрос с довольно полным ответом о различиях между calloc и malloc + 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-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;
    }

Ноэто не нормально, alloc_perturb безусловно, передал байт memset в 0xf, в отличие от восходящего потока, где он проверяет, установлен ли perturb_byte.Это должно быть изменено на

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

Патч, который я прикрепил, решает проблему для меня.

Эта проблема усугубляется тем фактом, что любой вид конфликта блокировки на результатах аренымы возвращаемся к mmap () и получаем новый фрагмент.Это потому, что мы проверяем, не повреждена ли неконтролируемая арена, которую мы проверяем, и делаем ли мы это циклично, и если мы переходим к началу, мы знаем, что ничего не нашли.За исключением случаев, когда наша начальная арена на самом деле не повреждена, мы по-прежнему возвращаем NULL, поэтому мы чаще прибегаем к этой функции mmap (), что действительно делает ее нестабильной.

Пожалуйста, исправьте это как можно скорееЯ бы даже зашел так далеко, что назвал это возможной проблемой безопасности.

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Вызов memset() гарантирует, что ОС фактически выполняет сопоставление виртуальной памяти.Как отмечено в ответах на вопрос, который вы связали, calloc() можно оптимизировать, чтобы отложить фактическое отображение памяти.

У приложения могут быть причины , а не отложить фактическое созданиеотображение виртуальной памяти - такое как использование буфера для чтения с очень высокоскоростного устройства, хотя в случае использования memset() для обнуления памяти использование calloc() вместо malloc() кажется избыточным.

0 голосов
/ 07 февраля 2019

Никто не совершенен, вот и все.Да, memset до нуля после calloc является экстравагантным.Если вам нужен явный memset, чтобы гарантировать, что вы обладаете запрошенной вами памятью, тогда вместо него должно следовать malloc.

Новый код содержит около 20 ошибок на 1000линии и законы вероятности подразумевают, что не все из них отсеяны.Кроме того, это не совсем ошибка, так как не наблюдается никакого плохого поведения.

0 голосов
/ 07 февраля 2019

Я бы назвал это ошибкой, поскольку он выполняет бессмысленную работу, calloc() определено для возврата уже очищенной памяти, так зачем очищать ее снова?Возможно, неудачный рефакторинг, когда кто-то переключился с malloc().

Если код имеет открытый исходный код и / или в репозитории, к которому у вас есть доступ, я бы проверил историю коммитов для этих строк и посмотрел, что былопродолжается.Если повезет, есть сообщение о коммите, которое говорит о мотивации ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...