C4996 (функция небезопасна) предупреждение для strcpy, но не для memcpy

Я пишу код в VS2010, и я вижу, что после компиляции компилятор выдает мне предупреждение C4996 ("Эта функция или переменная может быть небезопасна") для вызовов strcpy и sprintf.

Однако я не смог получить аналогичные предупреждения для memcpy (и, возможно, в коде есть еще несколько похожих "небезопасных" вызовов функций)

int _tmain(int argc, _TCHAR* argv[])
{
    char buf1[100], buf2[100];
    strcpy (buf1, buf2); // Warning C4996 displayed here asking to use strcpy_s instead
    memcpy (buf1, buf2, 100); // No warning here asking to use memcpy_s
    memcpy_s(buf1, 100, buf2, 100);
    return 0;
}

Почему это так? Как включить предупреждение C4996 для всех возможных небезопасных вызовов в моем коде?

7 ответов

Решение

В общем, для компиляции C-кода вам нужен соответствующий C-компилятор. Visual Studio - это несоответствующий компилятор C++.

Вы получаете предупреждение, потому что Visual Studio плохой. Смотрите это.

C4996 появляется всякий раз, когда вы используете функцию, которую Microsoft считает устаревшей. Очевидно, Microsoft решила, что они должны диктовать будущее языка C, а не рабочей группы ISO C. Таким образом вы получаете ложные предупреждения для совершенно прекрасного кода. Компилятор это проблема.

В функции strcpy() нет ничего плохого, это миф. Эта функция существует уже около 30-40 лет, и каждая ее часть должным образом документирована. Поэтому то, что делает функция, а что нет, не должно вызывать удивления даже у начинающих программистов на Си.

Что делает и не делает strcpy:

  • Он копирует строку с нулевым символом в конце в другую ячейку памяти.
  • Он не несет никакой ответственности за обработку ошибок.
  • Это не исправляет ошибки в приложении вызывающей стороны.
  • Он не несет никакой ответственности за обучение программистов на Си.

Из-за последнего замечания, приведенного выше, вы должны знать следующее перед вызовом strcpy:

  • Если вы передаете строку неизвестной длины в strcpy, не проверив ее заранее, у вас есть ошибка в приложении вызывающей стороны.
  • Если вы передаете некоторый кусок данных, который не заканчивается \0, у вас есть ошибка в приложении вызывающего абонента.
  • Если вы передадите два указателя в strcpy(), которые указывают на области памяти, которые перекрываются, вы вызываете неопределенное поведение. Это означает, что у вас есть ошибка в приложении вызывающей стороны.

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

strcpy небезопасно, если прекращение NUL отсутствует, так как может скопировать больше символов, чем умещается в целевой области. С memcpyколичество скопированных байтов является фиксированным.

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

Включить в заголовок "stdafx.h" определение

#define _CRT_SECURE_NO_WARNINGS

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

Вы получаете эти предупреждения, потому что не передавая длину строки и полагаясь на \0 завершение небезопасно, так как может вызвать переполнение буфера. В memcpy вы передаете длину, поэтому проблема переполнения отсутствует.

Вы можете использовать что-то вроде

#ifdef _MSC_VER
#  pragma warning(push)
#  pragma warning(disable:4996)
#endif
strcpy... ;  // Code that causes unsafe warning
#ifdef _MSC_VER
#  pragma warning(pop)
#endif

Если вы не беспокоитесь о переносимости, вы можете использовать альтернативы, такие как strcpy_s так далее

Предупреждение означает, что эта функция устарела и не будет доступна в следующих версиях: http://msdn.microsoft.com/en-US/en-en/library/ttcz0bys.aspx Вы не можете добавлять другие функции в устаревшую список Microsoft.

Причина устаревания "небезопасная", но она отличается от вашего предположения "C4496 показывает все небезопасные функции".

Причина, по которой вы получаете предупреждение о sprintf а также strcpyи не на memcpy, это потому что memcpy имеет параметр длины, который ограничивает объем памяти, которую вы копируете. За strcpy а также memcpyввод должен завершаться \0, Если нет, то это будет продолжаться вне пределов. Вы можете ограничить это с помощью snprintf а также strncpy функции. Те неявно ограничивают, сколько можно скопировать.

Обратите внимание, что Microsoft устарела snprintf, так что вы должны использовать функцию замены _snprintf вместо. Однако это особая функция MSVC.

Я бы посоветовал покончить с char * буферизируют все вместе и переключаются на C++, используя контейнер stl, такой как std::string, Это избавит вас от головной боли при отладке и сделает ваш код переносимым.

Так как strcpy а также sprintf на самом деле небезопасные функции, это зависит от содержимого строки, чтобы не переполнить. Вместо этого вы должны использовать strncpy а также snprintf чтобы убедиться, что он не перезаписывает память.

В то время как memcpy это не тот случай, он имеет длину, поэтому он не перезаписывает память, пока длина верна.

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