【问题标题】:Warning C4996: This function or variable may be unsafe -- compared to GCC on POSIX警告 C4996:与 POSIX 上的 GCC 相比,此函数或变量可能不安全
【发布时间】:2011-05-16 06:36:11
【问题描述】:

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

【问题讨论】:

  • IMO,g++ 根本不认为通知您“不安全”功能是它的职责。就 VC++ 而言,实际上整个 C 标准库都被认为是不安全的。
  • 但是你提到的函数之间的区别在于,在一种情况下,free 返回的指针是你的责任。
  • @UncleBen:我认为这不是真的。我刚刚在 Linux 上与 MS 的 crtdbg.h 和 Valgrind 确认了一个简单的单行程序 int main(){getenv("PATH");} 并且都报告没有内存泄漏:P 事实上,int main(){free(getenv("PATH"));} 会产生一个断言错误。
  • VC++ 的getenv 看起来已经是线程安全的了(你可以自己检查源代码,它在getenv.c 中);我想弃用是由于非const 返回值造成的,这使得在没有类型系统甚至警告您这种可能性的情况下写入内部缓冲区末尾的可能性仍然存在。但这只是一个猜测,因为似乎没有任何记录在案的理由来解释这些……

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


【解决方案1】:
  1. 在一个理智的世界里,答案是“当然不是,那太愚蠢了!”然而,在这个世界上,似乎没有尽头的令人痛苦的深思熟虑的无证行为,人们将弯腰依赖这些行为。 Raymond Chen 在他的博客中收集了大量此类轶事(轶事?)。如the hideous practice of using a bug in the loader to share thread-local variables between an exe and a DLL。当您拥有与 Microsoft 一样多的客户时,唯一安全的选择就是永远不要冒险破坏向后兼容性。

  2. 警告的不同是因为cl.exe 会竭尽全力突出潜在的安全问题,而g++ 不会。 getenvputs 和朋友们在 POSIX 下仍然被破坏,但是(至少对于 getenv)在标准库中没有更安全的替代方案。而且,与 Microsoft 不同的是,GNU 人可能认为存在潜在安全问题的标准库调用比更安全但特定于平台的库调用更不邪恶。

【讨论】:

    【解决方案2】:

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

    只需设置 _CRT_SECURE_NO_WARNINGS 并完成它。实在是太傻了。

    【讨论】:

    • 可能与他们添加“您确定要执行吗?是/否”消息的原因相同。人们......好吧,不是一直那么聪明:)
    【解决方案3】:

    对于getenv的具体情况,确实不是可重入的,也不是线程安全的。至于为什么微软不直接替换它,你不能拿那个接口让它可重入(你几乎可以用线程本地存储让它“线程安全”,但它仍然不能重入)。

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

    真的,如果您有多个线程,则将环境变量用于“在进程开始之前或在进程开始时设置它,并且只从该点开始读取它”之外的任何东西都可能会以泪水告终。 setenvputenv 没有足够丰富的接口来表达“原子地设置这组环境变量”之类的东西,同样getenv 也没有办法表达“原子地读取这组环境变量” .

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

    【讨论】:

    • 好点。遵循您的逻辑-MS 已弃用的警告确实是多余的。以getenv 为例: 1) GetEnvironmentVariable 可能无法解决重入问题,但它并未“被弃用”。 2)如果我真的想保护我的代码并去实现一个博士级线程安全的严格算法包装器,它仍然会在某个时候调用getenv,所以按照 MSVC 的定义,我仍然不安全。 (除非我疏远了标准,屈服于 MS 特定的领域)
    猜你喜欢
    • 2012-11-13
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 2016-10-28
    相关资源
    最近更新 更多