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

时间:2010-11-26 16:21:27

标签: c++ windows visual-c++ gcc

我注意到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这样的东西,它们完全改变签名并处理缓冲区大小。但不会改变这个问题的核心

3 个答案:

答案 0 :(得分:23)

  1. 在一个理智的世界里,答案是“当然不是,这将是愚蠢的!”然而,在这个世界上,似乎没有任何一种根本没有思考的无证行为,人们会依赖这种行为。 Raymond Chen在他的博客中收集了很多这样的轶事(ane???)。例如the hideous practice of using a bug in the loader to share thread-local variables between an exe and a DLL。如果您拥有的客户数量与微软一样多,那么唯一安全的选择就是不要冒险破坏向后兼容性。

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

答案 1 :(得分:9)

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

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

答案 2 :(得分:7)

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

即使您只是完全取消getenv,仍然存在这样的问题:您需要environ变量,这需要一些严格的编译器级别支持才能使线程安全,因为它只是数据。

实际上,将环境变量用于“在进程开始之前或进程开始之前进行设置,并且仅从该点开始进行设置”,如果您有多个线程,则可能会结束。 setenvputenv没有足够丰富的界面来表达“原子地设置这组环境变量”这样的内容,同样getenv无法表达“读取此内容”原子地设置环境变量“。

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