为什么 GCC 仅仅通过将其放入循环中就被欺骗以允许未定义的行为?

2024-02-11

以下内容是无意义的,但可以干净地编译g++ -Wall -Wextra -Werror -Winit-self(我测试了GCC 4.7.2和4.9.0):

#include <iostream>
#include <string>

int main()
{
  for (int ii = 0; ii < 1; ++ii)
  {
    const std::string& str = str; // !!
    std::cout << str << std::endl;
  }
}

所标记的线!!导致未定义的行为,但未被 GCC 诊断。然而,注释掉for这条线让海湾合作委员会抱怨:

error: ‘str’ is used uninitialized in this function [-Werror=uninitialized]

我想知道:为什么GCC在这里这么容易被愚弄?当代码不在循环中时,GCC 知道它是错误的。但是将相同的代码放在一个简单的循环中,GCC 就不再理解了。这让我很困扰,因为当我们在 C++ 中犯下愚蠢的错误时,我们非常依赖编译器来通知我们,但在看似微不足道的情况下它却失败了。

奖金琐事:

  • 如果你改变std::string to int and打开优化,GCC 即使使用循环也会诊断错误。
  • 如果您使用以下命令构建损坏的代码-O3,GCC 从字面上调用 ostream 插入函数,并使用字符串参数的空指针。如果您认为如果没有进行任何不安全的转换,就不会受到空引用的影响,请再想一想。

我已为此提交了一个 GCC 错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63203 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63203- 我仍然想更好地了解出了什么问题以及它如何影响类似诊断的可靠性。


我仍然想更好地了解出了什么问题以及它如何影响类似诊断的可靠性。

与 Clang 不同,GCC 没有检测自初始化引用的逻辑,因此在这里获取警告依赖于检测未初始化变量的使用的代码,这是相当不稳定且不可靠的(请参阅更好的未初始化警告 https://gcc.gnu.org/wiki/Better_Uninitialized_Warnings供讨论)。

With an int编译器可以发现你写了一个未初始化的int到流,但带有std::string类型表达式之间显然有太多抽象层std::string并得到const char*它包含,并且 GCC 无法检测到该问题。

例如只要您启用一些优化,GCC 就会对变量声明和使用之间代码较少的更简单示例发出警告:

extern "C" int printf(const char*, ...);

struct string {
  string() : data(99) { }
  int data;
  void print() const { printf("%d\n", data); }
};

int main()
{
  for (int ii = 0; ii < 1; ++ii)
  {
    const string& str = str; // !!
    str.print();
  }
}

d.cc: In function ‘int main()’:
d.cc:6:43: warning: ‘str’ is used uninitialized in this function [-Wuninitialized]
   void print() const { printf("%d\n", data); }
                                           ^
d.cc:13:19: note: ‘str’ was declared here
     const string& str = str; // !!
                   ^

我怀疑这种缺失的诊断只会影响少数依赖启发式方法来检测问题的诊断。这些将给出以下形式的警告“may未初始化时使用”或“may违反严格的别名规则”,并且可能会出现“数组下标高于数组边界”警告。这些警告不是 100% 准确,并且像循环(!)这样的“复杂”逻辑可能会导致编译器放弃尝试分析代码并失败进行诊断。

恕我直言,解决方案是在初始化时添加对自初始化引用的检查,而不是依赖于稍后使用时检测它是否未初始化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 GCC 仅仅通过将其放入循环中就被欺骗以允许未定义的行为? 的相关文章

随机推荐

  • 限制 Laravel 日志文件大小

    我是 Laravel 的新手 我们使用的是 Laravel 5 8 我看过一些恐怖故事 其中日志设置为每日轮换 但仍然达到 1GB 以上 我看到有人的日志一夜之间达到了 400GB 以上 有没有办法分割日志文件和 限制可以创建的总日志大小
  • SSE 4 popcount 为 16 个 8 位值?

    我有以下代码 它使用标志与 GCC 进行编译 msse4但问题是弹出计数仅获取转换后的最后四个 8 位 m128i类型 基本上我想要的是计算里面的所有 16 个数字 m128i类型 但我不确定创建变量后要调用什么内部函数popA 不知何故p
  • 如果只使用一次本地函数,那么使用它们还有什么意义吗?

    想象一下我有这样的代码 public void Foo Do bar work Do baz work Do foobar work 我意识到我可以 而且应该因为它做了不止一件事 将其重构为 public void Foo bar baz
  • PHP - 从数组中选择随机值?

    PHP 如何从数组中选取随机值 Example trees appletree gt id gt 12378 age gt 15 height gt 6 bananatree gt id gt 344343453 age gt 16 hei
  • 使用 VB 写入大量记录以进行访问

    我目前正在 Visual Studio 中编写一些软件 以使用 SQL 分析来自 Access 数据库的大量数据 我有代码可以创建一个新的计算变量 但我很难解决将数据写回 Access 所需的时间 我目前正在使用一些 vb com 代码与在
  • Java 消息服务 (JMS) 的用途是什么?

    我目前正在评估 JMS 但不知道它可以用来做什么 目前 我相信这将是一个用例 我想创建一个 SalesInvoice PDF 并在 SalesOrder 离开仓库时打印它 因此在交付事务期间 我可以发送一个事务打印请求 该请求在 Sales
  • OkHttpClient 的 NoClassDefFoundError

    在 gradle 中添加 facebook 依赖项后 我收到此运行时错误 compile com facebook android facebook android sdk 4 6 0 请注意 我也在使用 okhttp compile co
  • 用于移动物体的近似增量最近邻算法

    Bounty 这个问题提出了几个问题 赏金将用于全面解决这些问题的答案 这是我一直在玩的一个问题 NOTE我对以下解决方案特别感兴趣不基于欧几里得空间 有一组 Actor 形成大小为 K 的人群 距离d ActorA ActorB 对于任何
  • 避免 C++11 原始字符串文字中的第一个换行符?

    C 11 中的原始字符串文字非常好 只是格式化它们的明显方式会导致多余的换行符 n作为第一个字符 考虑这个例子 some code std string text R This is the first line This is the s
  • 使用 PHP 将下拉列表中的数据插入数据库

    首先 我需要一个可以轻松更新的下拉列表 因此我创建了一个名为 制造商 我在表格中列出了要选择的制造商 我终于用这段代码完成了这个
  • 在 Rust 中使用 Any 和特征 [重复]

    这个问题在这里已经有答案了 我正在尝试实施PartialEq在 Rust 中寻找具有子类型的特征 以便我可以将它们作为装箱指针添加到容器中 然后比较它们 这是我的缩小版实现 use std any Any trait Foo Any str
  • 编写一个递归函数来反转输入字符串

    我一直在读 C For Every 一书 其中一个练习说要编写一个函数string reverse string str 其中返回值是相反的str 有人可以写一些基本代码并向我解释吗 从昨天开始我就一直盯着这个问题 想不通 我得到的最远的是
  • 忽略 jax-rs 中传入的 json 元素

    我想知道该放在哪里 JsonIgnoreProperties ignoreUnknown true 在 Java REST API 中 我有以下课程 import org codehaus jackson annotate JsonIgno
  • 从按钮重新启动 Intro.Js 之旅?

    有没有办法通过按钮重新启动 Intro Js 我目前已将其设置为在页面加载时运行 并使用 JSON 中定义的步骤运行 效果很好 不过 我希望用户可以通过帮助按钮访问该导览 以便在需要时进行参考 我努力了 introJs setOptions
  • 将 Entity Framework 4.0 与 WCF 4.0 一起使用时出现 DataContractSerializer 错误

    我尝试通过 WCF 从实体框架检索对象列表 但收到以下异常 尝试序列化参数时出错http tempuri org GetAllResult http tempuri org GetAllResult InnerException 消息为 类
  • Android 模拟器警告访客未在线 - 如何关闭新的快速启动功能?

    我有过一次非常糟糕的使用经历模拟器快速启动 https android developers googleblog com 2017 12 quick boot top features in android html 它假设允许模拟器在
  • Powermock mockstatic 无法子类化最终类

    我想模拟最后一堂课 PowerMockito mockStatic TestFinalClass class 当我运行单个 junit 并将 javaagent 添加到我的 VM 参数时 它正在从我的 Eclipse 中运行 javaage
  • 如何隐藏 iPhone 标签栏?

    我有一个小型多视图应用程序 它由一个UITabBarController每个选项卡中都有一个导航控制器 我想要的是展示一个UIImageView当用户摇动设备时 在我实现了加载之后UIImageView 我遇到了一个问题 由于选项卡和导航栏
  • IE10控制台无法通过命令document.cookie看到cookie

    IE10控制台无法通过命令看到cookiedocument cookie 但请在请求中发送它们 Update 有趣的是 我正在使用 10 0 9200 16519 它似乎按预期为我工作
  • 为什么 GCC 仅仅通过将其放入循环中就被欺骗以允许未定义的行为?

    以下内容是无意义的 但可以干净地编译g Wall Wextra Werror Winit self 我测试了GCC 4 7 2和4 9 0 include