Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
Про разницу между strlcat и strncat

Про разницу между strlcat и strncat

16 Июл 2019

Пока идёт активная подготовка больших статей про проверку кода операционной системы Haiku OS, я хочу привести один пример популярной ошибки с функцией strncat из этого проекта. Освежить знания по этой теме будет полезно для всех C и C++ разработчиков.

0640_strncat_strlcat_ru/image1.png

Описание функций

Функция strncat служит для конкатенации строк и имеет следующую сигнатуру:

char *strncat(char *dest, const char *src, size_t n);

Она добавляет не более n символов из строки src к строке dest, при этом строка src может не заканчиваться терминальным нулём. В строке dest должно быть достаточно места, иначе поведение программы становится непредсказуемым из-за переполнения буфера, т.к. функция не производит контроля границ.

Функция strlcat служит для конкатенации строк и делает это более безопасно, чем функция strncat. strlcat имеет следующую сигнатуру:

size_t strlcat(char *dst, const char *src, size_t size)

В отличие от других функций, она принимает полный размер буфера и гарантирует наличие терминального символа у результата. Для корректной работы функции strlcat, ей необходимо передавать только нультерминальные строки.

Ошибка в Haiku OS

V645 The 'strncat' function call could lead to the 'output' buffer overflow. The bounds should not contain the size of the buffer, but a number of characters it can hold. NamespaceDump.cpp 101

static void
dump_acpi_namespace(acpi_ns_device_info *device, char *root, int indenting)
{
  char result[255];
  char output[320];
  char tabs[255] = "";
  char hid[16] = "";
  int i;
  size_t written = 0;
  for (i = 0; i < indenting; i++)
    strlcat(tabs, "|    ", sizeof(tabs));

  strlcat(tabs, "|--- ", sizeof(tabs));
  ....
  void *counter = NULL;
  while (....) {
    uint32 type = device->acpi->get_object_type(result);
    snprintf(output, sizeof(output), "%s%s", tabs, result + depth);
    switch(type) {
      case ACPI_TYPE_INTEGER:
        strncat(output, "     INTEGER", sizeof(output));
        break;
      case ACPI_TYPE_STRING:
        strncat(output, "     STRING", sizeof(output));
        break;
      case ACPI_TYPE_BUFFER:
        strncat(output, "     BUFFER", sizeof(output));
        break;
      case ACPI_TYPE_PACKAGE:
        strncat(output, "     PACKAGE", sizeof(output));
        break;
      ....
      case ACPI_TYPE_MUTEX:
        strncat(output, "     MUTEX", sizeof(output));
        break;
      case ACPI_TYPE_REGION:
        strncat(output, "     REGION", sizeof(output));
        break;
      case ACPI_TYPE_POWER:
        strncat(output, "     POWER", sizeof(output));
        break;
      case ACPI_TYPE_PROCESSOR:
        strncat(output, "     PROCESSOR", sizeof(output));
        break;
      case ACPI_TYPE_THERMAL:
        strncat(output, "     THERMAL", sizeof(output));
        break;
      case ACPI_TYPE_BUFFER_FIELD:
        strncat(output, "     BUFFER_FIELD", sizeof(output));
        break;
      case ACPI_TYPE_ANY:
      default:
        break;
    }
    ....
  }
  ....
}

Анализатор обнаружил смешанный код, состоящий из вызовов функций strlcat и strncat. Причём, вызовы функции strlcat являются корректными:

char tabs[255] = "";
....
strlcat(tabs, "|--- ", sizeof(tabs));

в них передаётся нультерминальная строка и размер всего буфера.

В то же время, многочисленные вызовы strncat в цикле являются ошибочными и могут привести к ошибке:

char output[320];
....
strncat(output, "     INTEGER", sizeof(output));

Программа долгое время может работать стабильно, если на вход функции поступают только короткие строки, но в цикле лимит буфера можно быстро исчерпать.

Заключение

Полезные ссылки по теме:

P.S.

Не дожидаясь публикации основных больших статей , мы отправили отчёт разработчикам Haiku OS, и они уже приступили к исправлению ошибок: https://git.haiku-os.org/haiku/log/?qt=grep&q=pvs

Популярные статьи по теме


Комментарии (0)

Следующие комментарии next comments
close comment form
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам