我注意到MS编译器为cstdlib
函数提供了“已弃用”警告,例如getenv
。 MS发明了自己的标准,例如_dupenv_s
。
AFAIK主要的“不安全”事情是关于重入*。由于MS的CRT被标记为“多线程”(/MT
),为什么它们不能用可重入的线程安全版本替换getenv
?是否有人会依赖不安全的行为?
我使用GCC g++ -Wall -Wextra -Weff++ -pedantic foo.cpp
编译了相同的代码,但它不会产生任何警告。所以我猜这不是POSIX的问题?这是怎么解决的? (好吧,也许他们只是改变了getenv
的行为,很高兴确认这一点。)
* 说它只是关于重入是一种过于概括的说法。当然,我们有像strncpy_s
这样的东西,它们完全改变签名并处理缓冲区大小。但不会改变这个问题的核心
答案 0 :(得分:23)
在一个理智的世界里,答案是“当然不是,这将是愚蠢的!”然而,在这个世界上,似乎没有任何一种根本没有思考的无证行为,人们会依赖这种行为。 Raymond Chen在他的博客中收集了很多这样的轶事(ane???)。例如the hideous practice of using a bug in the loader to share thread-local variables between an exe and a DLL。如果您拥有的客户数量与微软一样多,那么唯一安全的选择就是不要冒险破坏向后兼容性。
警告的不同之处在于cl.exe
正在竭力强调潜在的安全问题,而g++
则不然。 getenv
和puts
以及朋友们在POSIX下仍然被打破,但(至少对于getenv
)标准库中没有更安全的替代方案。并且,与Microsoft不同,GNU人员可能会看到标准库调用具有潜在的安全问题,而不是更安全但特定于平台的库调用。
答案 1 :(得分:9)
微软选择这样做让我感到很恼火。我知道如何安全地调用所有功能,我不想要或不需要这些额外的警告。
只需设置_CRT_SECURE_NO_WARNINGS即可完成。真的很傻。
答案 2 :(得分:7)
对于getenv
的特定情况,它确实不是可重入或线程安全的。至于微软为什么不只是替换它,你不能把它接受并使它可以重入(你几乎可以使用线程本地存储“线程安全”,但它仍然不是可重入的。)
即使您只是完全取消getenv
,仍然存在这样的问题:您需要environ
变量,这需要一些严格的编译器级别支持才能使线程安全,因为它只是数据。
实际上,将环境变量用于“在进程开始之前或进程开始之前进行设置,并且仅从该点开始进行设置”,如果您有多个线程,则可能会结束。 setenv
和putenv
没有足够丰富的界面来表达“原子地设置这组环境变量”这样的内容,同样getenv
无法表达“读取此内容”原子地设置环境变量“。
_dupenv_s
在我看来有些愚蠢,因为如果使用它突然使你的代码安全,它可能以一种安全的方式与getenv完成。 _dupenv_s
在多线程场景中使用环境变量解决了一小部分问题。