警告C4996:此功能或变量可能不安全 - 与POSIX上的GCC相比

kiz*_*zx2 20 c++ windows gcc visual-c++

我注意到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可以完全改变签名并处理缓冲区大小.但并没有改变这个问题的核心

Ben*_*rel 23

  1. 在一个理智的世界里,答案是"当然不是,这将是愚蠢的!" 然而,在这个世界上,似乎没有任何一种根本没有思考的无证行为,人们会依赖这种行为.Raymond Chen在他的博客中收集了很多这样的轶事(一些轶事?).比如在加载器中使用bug来共享exe和DLL之间的线程局部变量的可怕做法.当您拥有与Microsoft一样多的客户时,唯一安全的选择是从不冒险破坏向后兼容性.

  2. 警告的不同之处在于cl.exe,它正在不断强调潜在的安全问题,而g++不是.getenv并且puts朋友们在POSIX下仍然被打破,但是(至少对于getenv)标准库中没有更安全的替代方案.并且,与Microsoft不同,GNU人员可能会看到标准库调用具有潜在的安全问题,而不是更安全但特定于平台的库调用.


Jos*_*hua 9

微软选择这样做让我感到很恼火.我知道如何安全地调用所有功能,我不想要或不需要这些额外的警告.

只需设置_CRT_SECURE_NO_WARNINGS即可完成.真的很傻.

  • 可能与他们添加的原因相同_"您确定要执行<action>吗?是/否"_消息.人们......好吧,不是那么聪明:) (4认同)

Log*_*ldo 7

对于特定情况getenv,它确实不是可重入或线程安全的.至于为什么微软不只是替换它,你不能采用该接口并使其可重入(你几乎可以使用线程本地存储使其"线程安全",但它仍然不会是可重入的).

即使你只是getenv完全拿走了,仍然存在这样的问题:你有一个environ变量需要一些严格的编译器级支持才能使线程安全,因为它只是数据.

实际上,使用环境变量除了"在进程开始之前或进程开始之前进行设置,并且只从那一点开始从中进行读取"时,如果你有多个线程,则可能会结束.setenv并且putenv没有足够丰富的接口来表达诸如"原子地设置这组环境变量"之类的东西,同样getenv没有办法表达"原子地读取这组环境变量".

_dupenv_s在我看来有些愚蠢,因为如果使用它突然使你的代码安全,它可能可以用getenv以安全的方式完成._dupenv_s在多线程场景中使用环境变量解决了一小部分问题.

  • 好点.按照你的逻辑 - MS的弃用警告实际上是多余的.以`getenv`为例:1)`GetEnvironmentVariable`可能无法解决重入问题,但它并未"弃用".2)如果我真的想保护我的代码去实现一个博士级的线程安全的严格算法的包装,它仍然会调用`getenv`在某些时候,所以我仍然MSVC的定义不安全.(除非我疏远标准并屈服于特定于MS的领域) (4认同)