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

21

我注意到MS编译器会对cstdlib函数,如getenv发出"已弃用"警告。MS发明了自己的标准,比如_dupenv_s

问题1

据我所知,主要的"不安全"问题是关于可重入性的*。由于MS的CRT被标记为"多线程"(/MT),为什么他们不只是用可重入、线程安全的版本来代替getenv?这是因为任何人都会依赖于不安全的行为吗?

问题2

我使用GCC编译相同的代码g++ -Wall -Wextra -Weff++ -pedantic foo.cpp,它没有产生任何警告。所以我猜在POSIX上这不是一个问题吗?这是如何解决的呢?(好吧,也许他们只是改变了getenv的行为,确认一下会很好)。

* 说它仅仅关于可重入性是过于概括。当然我们还有像strncpy_s这样完全改变签名并处理缓冲区大小的东西。但这不改变本质问题


5
就我看来,g++并不认为通知你“不安全”的函数是它的职责。至于VC ++,几乎整个C标准库都被视为不安全而弃用了。 - UncleBens
但是你提到的这些函数之间的区别在于,在某些情况下,你需要负责释放返回的指针。 - UncleBens
1
@UncleBen:我认为这不是真的。我刚刚用 MS 的 crtdbg.h 和 Linux 上的 Valgrind 对一个简单的一行程序 int main(){getenv("PATH");} 进行了确认,两者都没有报告内存泄漏 :P 实际上,int main(){free(getenv("PATH"));} 会导致断言错误。 - kizzx2
4
VC++ 的 getenv 看起来已经是线程安全的了(你可以自己查看源代码,它在 getenv.c 中);我想这个弃用是由于其非 const 返回值,这可能导致在没有类型系统警告的情况下写入超出内部缓冲区末尾的位置。但这只是一个猜测,因为似乎没有任何关于这一切的记录理由... - please delete me
3个回答

23
  1. 在一个理智的世界中,答案应该是“当然不行,那太愚蠢了!”。但在这个世界上,似乎有无数匪夷所思、未经充分考虑的行为,人们居然会依赖它们。Raymond Chen在他的博客中收集了一系列此类轶事(或许可以称之为"反面教材"?),比如使用加载器的一个bug来共享exe和DLL之间的线程本地变量的可怕做法。当你像Microsoft这样拥有如此多的客户时,唯一安全的选择就是从不冒险破坏向后兼容性。

  2. 警告的差异是因为cl.exe正在尽力突出一个潜在的安全问题,而g++则没有。getenvputs等函数在POSIX下仍然存在问题,但是(至少对于getenv)标准库中没有更安全的替代品。并且,与Microsoft不同,GNU的开发者可能认为具有潜在安全问题的标准库调用是一个较小的罪恶,而比起平台特定的库调用,则更胜一筹。


10

我非常不满意微软选择这样做。我知道如何安全地调用所有函数,我不想要或需要这些额外的警告。

只需设置_CRT_SECURE_NO_WARNINGS并完成它。就是这么简单愚蠢。


6
可能是因为他们添加了“您确定要执行<操作>吗?是/否”消息的同样原因。人们有时并不那么聪明 :) - default

7
对于特定情况下的getenv函数,它确实不是可重入或线程安全的。至于为什么微软不直接替换它,这是因为你不能将该接口变成可重入的(你几乎可以使用线程本地存储使其“线程安全”,但它仍然不是可重入的)。
即使你完全删除了getenv函数,还存在一个问题,那就是environ变量,它需要一些严格的编译器级别支持才能做到线程安全,因为它只是数据。
事实上,除了“在进程启动前或进程启动时设置它,并且从那时起只从中读取”之外,如果你有多个线程,使用环境变量来做任何其他事情可能会导致灾难。 setenvputenv没有足够丰富的接口来表达“原子地设置这组环境变量”,同样,getenv也没有一种方法来表达“原子地读取这组环境变量”。
在我看来,_dupenv_s有点傻,因为如果使用它可以使你的代码突然变得安全,那么使用getenv也可以以安全的方式完成。 _dupenv_s仅解决了在多线程场景下使用环境变量时的一小部分问题。

5
好观点。根据您的逻辑,微软的"不推荐使用"警告真的是多余的。以 "getenv" 为例:1)GetEnvironmentVariable 可能无法解决重入问题,但它并没有被"不推荐使用"。2)如果我真的想要保护我的代码,并实现一个博士级别的线程安全严格算法封装,它仍然会在某个时候调用 getenv,所以按照 MSVC 的定义,我仍然不安全。(除非我放弃标准并屈服于 MS 特定领域)。 - kizzx2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接