Подтвердить что ты не робот

Как избавиться от "небезопасных" предупреждений/ошибок в Visual Studio (strcpy, sprintf, strdup)

Я пытаюсь избавиться от некоторых предупреждений компилятора, которые говорят, что strcpy, sprintf и т.д. небезопасны. Я понимаю, почему они небезопасны, но я не могу придумать хороший способ исправить код в стиле С++.

Здесь выдержка из кода:

extList->names[i]=(char *)malloc(length*sizeof(char));
strcpy(extList->names[i],extName);                     // unsafe
// strncpy(extList->names[i],extName,length);          // also unsafe

Здесь сообщение:

C4996: 'strcpy': эта функция или переменная может быть небезопасный. Вместо этого рассмотрите возможность использования strcpy_s. Чтобы отключить устаревание, используйте _CRT_SECURE_NO_WARNINGS. Подробнее см. Интерактивную справку.

Я не могу думать о безопасном способе копирования данных на С++, не зная длины копируемого материала. Я знаю, что strlen(), но это также небезопасно, поскольку он предполагает (может быть, неправильно), что данные заканчиваются нулями.

также:

// used to concatenate:
sprintf(extStr,"%s%s",platExtStr,glExtStr);

C4996: 'sprintf': эта функция или переменная может быть небезопасной. Рассматривать используя sprintf_s. Чтобы отключить устаревание, используйте _CRT_SECURE_NO_WARNINGS. Подробнее см. Интерактивную справку.

Использование std::string для конкатенации достаточно просто, но тогда мне нужно каким-то образом получить данные в extStr (и не использовать strcpy, lol). Функция string:: c_str() возвращает указатель на un-modifiable data, поэтому я не могу просто установить extStr равным ему. (И я даже не уверен, должен ли указатель c_str() нуждаться в удалении, вызванном на нем позже? Распределяет ли пространство с помощью "new"?)

Какие-нибудь советы по этому поводу? Это часть файла с 10 000 строк, который не принадлежит мне... поэтому я не очень люблю переписывать вещь на С++.

4b9b3361

Ответ 1

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

Для win32/msvc в ProjectProperties → Свойства конфигурации → C/С++ → Препроцессор → Определения препроцессора, добавьте следующие макросы:

_CRT_SECURE_NO_DEPRECATE  
_CRT_NONSTDC_NO_DEPRECATE

Или вы можете передать thos в параметрах командной строки (-D_CRT_SECURE_NO_DEPRECATE). Вероятно, вы можете #define их в начале определенных файлов *.cpp. Кроме того, их, вероятно, больше (см. Crtdefs.h - похоже, их много...). Эти предупреждения обычно сообщают вам, с какими макросами вы можете их отключить - просто прочитайте вывод компилятора.

Ответ 2

Если избавиться от предупреждений, это ваша цель... просто определите это _CRT_SECURE_NO_WARNINGS и он будет подавлять все предупреждения об устаревании. Но это не устранит основные проблемы с небезопасными функциями CRT.

Если вы на Visual Studio версии >= 2005 и хотите исправить эти предупреждения правильно... Самый простой способ - #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 и #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 в вашем проекте.

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

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

Ниже приведен способ исправления вашего примера программно

strcpy_s(extList->names[i], length, extName); 

Ответ 3

Вот еще один ответ на этот вопрос.

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif

        strcpy(destination, source);

#ifdef _MSC_VER
#pragma warning(pop)
#endif

Ответ 4

Вы знаете, сколько копировать - вы выделили для этого место!

Неужели вы не захотите копировать больше, чем место, которое вы выделили?

Я бы предпочел использовать метод, который явно избегает переполнения буфера, ограничивая количество копируемых элементов. Когда я был программистом на C, мы использовали

dest = malloc(len);         // note: where did we get len?
if ( dest is null )  panic!  // note: malloc can fail
strncpy(dest, src, len);
dest[len-1] =0;

Это немного беспорядочно, и было указано, что он использует метод strncpy(), который изначально был предназначен для полей с фиксированной шириной, а не для строк. Однако он делает

Существуют такие методы, как strdup() и strlcpy(), которые мы можем вам помочь.

Мои рекомендации:

1). Ваша цель не должна состоять в том, чтобы подавлять предупреждения, но чтобы сделать код надежным.

2). При копировании строк вам необходимо обеспечить следующее:

  • Защитите себя от неправильного ввода, например, неиспользуемую или чрезмерно длинную строку.
  • Защитите себя от сбоев malloc,
  • Сильно предпочитайте копировать подсчитанные числа символов для копирования, пока мы не увидим нулевое значение
  • Если вы заявляете, что хотите построить строку, то решительно убедитесь, что null завершает ее.

Если strlcpy() доступен в вашей среде, вы можете использовать его, иначе почему бы не написать свою собственную небольшую полезность? Тогда, если в этой функции есть предупреждения, вы локализировали проблему.

Ответ 5

В первом примере вы уже знаете длину. Поскольку вы не выделяете length+1 байты, я предполагаю, что length ВКЛЮЧАЕТ нулевой ограничитель. В этом случае просто std::copy строка: std::copy(extName, extName + length, expList->names[i]);

В вашем втором примере, предполагая, что исходные строки имеют нулевое завершение, вы можете вычислить длину строки назначения и снова использовать std::copy для конкатенации вручную или вы можете использовать std::string и std::copy из результатов c_str в пункт назначения (опять же, полагая, что вам выделено достаточно места для него).

c_str() не выделяет память, для которой требуется внешнее удаление.

Наконец, обратите внимание, что sizeof(char) всегда будет одним и, следовательно, избыточным в вашем malloc, хотя число бит в этом символе может не быть 8 (см. CHAR_BIT).

Ответ 6

Я думаю, что вы должны заменить все функциональные вызовы , если возможно,, чтобы вызвать собственную реализацию. Хорошим примером здесь была бы функция замены strcpy и вызов в ней конкретной версии strcpy, основанной на компиляторе. Затем ваша реализация может быть легко модифицирована в соответствии с любым вашим компилятором, особенно если вы будете добавлять или изменять платформы/компиляторы.

Пример:


char* StringCopy(char* Destination, const char* Source, size_t DestinationSize)
{
#ifdef _MSC_VER
  return strcpy_s(Destination, Source, DestinationSize);
#else
  if(!(strlen(Source) >= DestinationSize))
     return strcpy(Destination, Source);
  else
     return 0x0;
#endif
}

Ответ 7

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

Ответ 8

Если этот код нужно компилировать только для платформы Windows, лучше использовать защищенную версию этих функций. Однако, если этот код собирается скомпилировать на нескольких платформах (linux, Aix и т.д.), Либо вы можете отключить предупреждение в файле конфигурации проекта Windows (например,.vcxproj) с помощью _CRT_SECURE_NO_WARNINGS или вы можете использовать фрагмент кода, например это в тех местах, где эти функции были вызваны в .cpp файле.

#if _OS_ == _OS__WINDOWS
//secure function call
#else
//already written code
#endif