警告 C4996:与 POSIX 上的 GCC 相比,此函数或变量可能不安全
我注意到 MS 编译器对 cstdlib
函数(例如 getenv
)发出“已弃用”警告。 MS 发明了自己的标准,例如 _dupenv_s
。
问题 1
据我所知,主要的“不安全”之处在于可重入*。既然 MS 的 CRT 被标记为“多线程”(/MT
),为什么他们不直接用可重入的线程安全版本替换 getenv
呢?是否有人会依赖不安全的行为?
问题 2
我用 GCC g++ -Wall -Wextra -Weff++ -pedantic foo.cpp
编译了相同的代码,它没有产生任何警告。所以我想这在 POSIX 上不是问题?这是怎么解决的呢? (好吧,也许他们只是改变了 getenv 的行为,如果能确认这一点就好了)。
* 说“它只是关于可重入”的说法过于笼统。当然,我们有像 strncpy_s
这样的东西,它完全改变了签名并处理缓冲区大小。但并没有改变这个问题的核心
I notice that MS compilers give "deprecated" warnings for cstdlib
functions like getenv
. MS has invented its own standard such as _dupenv_s
.
Question 1
AFAIK the main "unsafe" thing is about reentrancy *. Since MS's CRT is marked as "multi-threaded" (/MT
), why don't they just replace getenv
with the reentrant, thread-safe version? Is it like anybody would depend on the unsafe behavior?
Question 2
I compiled the same code with GCC g++ -Wall -Wextra -Weff++ -pedantic foo.cpp
and it doesn't yield any warnings. So I guess this is not a problem on POSIX? How is this solved? (OK maybe they just changed the behavior of getenv
, would be nice to have this confirmed).
* It's an over-generalization to say that its' only about reentrancy. Of course we have things like strncpy_s
which changes the signature completely and deals with buffer size. But doesn't change the core of this question
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在一个理智的世界中,答案将是“当然不是,那太愚蠢了!”然而,在这个世界上,似乎有无穷无尽的、令人痛苦的、未经深思熟虑的、未经记录的行为,人们会屈服于这些行为。 Raymond Chen 在他的博客中收集了大量此类轶事(轶事?)。例如利用加载器中的错误来共享线程局部变量的可怕做法exe 和 DLL 之间。当您拥有与 Microsoft 一样多的客户时,唯一安全的选择就是永远不要冒险破坏向后兼容性。
警告的差异是因为
cl.exe
会竭尽全力突出显示潜在的安全问题,而g++
则不然。getenv
和puts
等在 POSIX 下仍然无法正常工作,但是(至少对于getenv
),没有更安全的替代方案标准库。而且,与 Microsoft 不同的是,GNU 人员可能认为具有潜在安全问题的标准库调用比更安全但特定于平台的库调用危害较小。In a sane world, the answer would be "of course not, that would be stupid!" In this world, though, it seems there is no end of gut-wrenchingly poorly thought out undocumented behavior upon which people will stoop to depending upon. Raymond Chen has a great collection of such anecdotes (anecdon'ts?) in his blog. Such as the hideous practice of using a bug in the loader to share thread-local variables between an exe and a DLL. When you have as many customers as Microsoft does, the only safe choice is to never even risk breaking backwards compatibility.
The difference in warnings is because
cl.exe
is going out of its way to highlight a potential security problem, andg++
isn't.getenv
andputs
and friends are all still broken under POSIX, but (at least forgetenv
) there isn't a more secure alternative in the standard library. And, unlike Microsoft, the GNU folks probably see a standard library call with potential security problems as a lesser evil than a more secure but platform-specific library call.微软选择这样做让我很恼火。我知道如何安全地调用所有函数,我不想要或不需要这些额外的警告。
只需设置 _CRT_SECURE_NO_WARNINGS 即可完成。实在是太傻了。
It annoys the heck outta me that Microsoft chose to do this. I know how to call all the functions safely, I don't want or need these extra warnings.
Just set _CRT_SECURE_NO_WARNINGS and be done with it. It's really that silly.
对于
getenv
的具体情况,它确实不是可重入的或线程安全的。至于为什么微软不直接替换它,你不能采用该接口并使其可重入(你几乎可以使用线程本地存储使其“线程安全”,但它仍然不可重入)。即使您完全删除了
getenv
,仍然存在一个问题,即您拥有environ
变量,该变量需要一些严格的编译器级别支持才能确保线程安全,因为它是只是数据。实际上,如果您有多个线程,那么除了“在进程启动之前或进程启动时对其进行设置,并且仅从该点开始读取”以外的任何其他情况下使用环境变量可能会以泪水结束。
setenv
和putenv
没有足够丰富的接口来表达“原子地设置这组环境变量”之类的内容,同样getenv
也没有。没有办法表达“原子地读取这组环境变量”。在我看来,
_dupenv_s
有点愚蠢,因为如果使用它突然使您的代码变得安全,那么可能可以使用 getenv 以安全的方式完成。_dupenv_s
解决了在多线程场景中使用环境变量的一小部分问题。For the specific case of
getenv
, it is indeed not reentrant or thread safe. As for why Microsoft doesn't just replace it, you can't take that interface and make it reentrant (you can almost make it "thread safe" with thread local storage, but it would still not be reentrant).Even if you just took
getenv
away altogether, there is still the problem that you have theenviron
variable which would require some serious compiler level support to make thread safe, since it is just data.Really, using environment variables for anything other than "setting it up before the process starts or at process start, and only reading from it from that point on" is going to probably end in tears if you have more than one thread.
setenv
andputenv
don't have a rich enough interface to express something like "set this set of environment variables atomically" and likewisegetenv
doesn't have a way to express "read this set of environment variables atomically"._dupenv_s
is somewhat silly in my opinion, because if using that suddenly makes your code safe, it could probably done in a safe way with getenv._dupenv_s
solves a tiny subset of the problems with using environment variables in a multithreaded scenario.