Почему MSVC++ считает "std::strcat" небезопасным? (C++)

Когда я пытаюсь сделать что-то вроде этого:

char* prefix = "Sector_Data\\sector";
char* s_num = "0";
std::strcat(prefix, s_num);
std::strcat(prefix, "\\");

и так далее и тому подобное, я получаю предупреждение

warning C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead.

Почему strcat считается небезопасным, и есть ли способ избавиться от этого предупреждения без использования strcat_s?

Кроме того, если единственный способ избавиться от предупреждения - это использовать strcat_s, как это работает (по синтаксису: очевидно, он не принимает два аргумента).

7 ответов

Решение

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

strcat_s решает эту проблему, заставляя вас указывать длину буфера, в который вы копируете строку; при необходимости он обрезает строку, чтобы убедиться, что буфер не переполнен.

Google Strcat_s, чтобы увидеть, как именно его использовать.

Если вы используете C++, почему бы не избежать всего беспорядка и использовать std::string, Тот же пример без ошибок будет выглядеть так:

std::string prefix = "Sector_Data\\sector";
prefix += "0";
prefix += "\\"

не нужно беспокоиться о размерах буфера и тому подобном. И если у вас есть API, который принимает const char *Вы можете просто использовать .c_str() член;

some_c_api(prefix.c_str());

Вы можете избавиться от этих предупреждений, добавив:

_CRT_SECURE_NO_WARNINGS

а также

_SCL_SECURE_NO_WARNINGS

к определениям препроцессора вашего проекта.

Чтобы отключить предупреждение, вы можете сделать это.

#pragma warning(disable:4996)

Кстати, я настоятельно рекомендую вам использовать strcat_s().

Потому что он не имеет возможности проверить, будет ли строка назначения (префикс) в вашем случае записана за ее пределами. strcat по сути работает зацикливанием, копируя побитовую строку источника в место назначения. Он останавливается, когда видит значение "0" (обозначается как "\0"), называемое нулевым терминалом. Поскольку в C нет встроенной проверки границ, а dest str - это просто место в памяти, strcat будет продолжать работать до бесконечности, даже если он пройдет мимо источника str или dest. У str нет нулевого терминала.

Приведенные выше решения зависят от платформы вашей среды Windows. Если вы хотите что-то независимое от платформы, вы должны поспорить с strncat:

strncat(char* dest, const char* src, size_t count)

Это еще один вариант, когда используется разумно. Вы можете использовать счетчик, чтобы указать максимальное количество символов для копирования. Чтобы сделать это, вы должны выяснить, сколько места доступно в dest (сколько вы выделили - strlen(dest)) и передать это как count.

Это одна из функций манипуляции со строками в C/C++, которая может привести к ошибкам переполнения буфера.

Проблема в том, что функция не знает, каков размер буферов. Из документации MSDN:

Первый аргумент, strDestination, должен быть достаточно большим, чтобы объединить текущие strDestination и strSource и закрывающий '\0'; в противном случае может произойти переполнение буфера.

strcat_s принимает дополнительный аргумент, указывающий размер буфера. Это позволяет ему проверять размеры перед выполнением конкатата и предотвращает переполнение. См. http://msdn.microsoft.com/en-us/library/d45bbxx4.aspx

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

if(pDest+strlen(pDest)+strlen(pScr) < destSize)

Вы должны пройтись по всей длине обеих строк, просто чтобы убедиться, что они подойдут, прежде чем идти вниз по всей длине СНОВА, чтобы сделать копию. Из-за этого многие программисты просто предполагают, что он подойдет и пропустят тест. Хуже того, может случиться так, что когда код впервые написан, он ГАРАНТИРУЕТСЯ подгонять, но когда кто-то добавляет другую strcat или изменяет размер буфера или константу где-то еще в программе, у вас теперь есть проблемы.

Другая проблема, если pSrc и pDst перекрываются. В зависимости от вашего компилятора strcat вполне может быть простым циклом, который проверяет символ за раз на 0 в pSrc. Если pDst перезаписывает это 0, то вы попадете в цикл, который будет выполняться до сбоя вашей программы.

Другие вопросы по тегам