Почему MSVC ++ считает "std :: strcat" небезопасным? (C ++) - PullRequest
6 голосов
/ 01 июня 2009

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

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 ]

29 голосов
/ 02 июня 2009

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

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

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

some_c_api(prefix.c_str());
27 голосов
/ 02 июня 2009

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

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

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

4 голосов
/ 02 июня 2009

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

#pragma warning(disable:4996)

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

4 голосов
/ 02 июня 2009

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

_CRT_SECURE_NO_WARNINGS

и

_SCL_SECURE_NO_WARNINGS

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

4 голосов
/ 02 июня 2009

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

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

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

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

3 голосов
/ 02 июня 2009

Потому что у него нет возможности проверить, будет ли строка назначения (префикс) в вашем случае записана за ее пределами. 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.

0 голосов
/ 02 июня 2009

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

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

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

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

...