Предупреждение C4996: эта функция или переменная может быть небезопасной - по сравнению с GCC на POSIX
Я замечаю, что компиляторы MS дают "устаревшие" предупреждения для cstdlib
функций типа getenv
. MS изобрела свой собственный стандарт, такой как _dupenv_s
.
Вопрос 1
AFAIK главная "небезопасная" вещь - это повторное участие *. Поскольку MS CRT помечен как "многопоточное" (/MT
), почему бы просто не заменить getenv
на реентерабельную, потокобезопасную версию? Похоже, что кто-то будет зависеть от небезопасного поведения?
Вопрос 2
Я скомпилировал тот же код с GCC g++ -Wall -Wextra -Weff++ -pedantic foo.cpp
, и он не дает никаких предупреждений. Итак, я думаю, это не проблема на POSIX? Как это решить? (ОК, возможно, они просто изменили поведение getenv
, было бы хорошо, если бы это подтвердилось).
* Это чрезмерное обобщение, чтобы сказать, что его "только о возврате". Конечно, у нас есть такие вещи, как strncpy_s
, который полностью меняет подпись и имеет дело с размером буфера. Но не меняет суть этого вопроса.
Ответы
Ответ 1
-
В здравом мире ответ будет "конечно, нет, это было бы глупо!" В этом мире, однако, кажется, что нет конца ужасно плохо продуманного недокументированного поведения, от которого люди будут опускаться в зависимости от. Раймонд Чен имеет большую коллекцию таких анекдотов (anecdon'ts?) в своем блоге. Например, отвратительная практика использования ошибки в загрузчике для обмена потоковыми локальными переменными между exe и DLL. Когда у вас так много клиентов, как Microsoft, единственный безопасный выбор - никогда не рискуйте нарушить совместимость.
-
Разница в предупреждениях заключается в том, что cl.exe
делает все возможное, чтобы выделить потенциальную проблему безопасности, а g++
- нет. getenv
и puts
, а друзья все еще разбиты под POSIX, но (по крайней мере, для getenv
) в стандартной библиотеке нет более безопасной альтернативы. И, в отличие от Microsoft, люди GNU, вероятно, видят стандартный вызов библиотеки с потенциальными проблемами безопасности как меньшее зло, чем более безопасный, но специфичный для платформы вызов библиотеки.
Ответ 2
Это раздражает то, что Microsoft решила сделать это. Я знаю, как безопасно вызывать все функции, я не хочу или не нуждаюсь в этих дополнительных предупреждениях.
Просто установите _CRT_SECURE_NO_WARNINGS и сделайте с ним. Это действительно так глупо.
Ответ 3
В конкретном случае getenv
он действительно не является реентерабельным или потокобезопасным. Что касается того, почему Microsoft не просто заменяет его, вы не можете взять этот интерфейс и сделать его реентерабельным (вы можете почти сделать его "потокобезопасным" с локальным хранилищем потоков, но он все равно не будет реентерабельным).
Даже если вы просто удалили getenv
в целом, по-прежнему существует проблема, что у вас есть переменная environ
, которая потребует некоторой серьезной поддержки уровня компилятора для обеспечения безопасности потоков, поскольку это всего лишь данные.
Действительно, используя переменные среды для чего-либо, кроме "настройки его перед запуском процесса или при запуске процесса, и только чтение из него с этой точки", вероятно, закончится слезами, если у вас есть несколько потоков. setenv
и putenv
не имеют достаточно богатого интерфейса, чтобы выразить что-то вроде "установить этот набор переменных среды атомарно", а также getenv
не имеет возможности выразить "читать этот набор переменных среды атомарно",
_dupenv_s
, по-моему, несколько глупо, потому что, если вы используете это, что делает ваш код безопасным, его можно, вероятно, сделать безопасным способом с getenv. _dupenv_s
решает крошечное подмножество проблем с использованием переменных среды в многопоточном сценарии.