即使不涉及签名类型,为什么 std::push_heap 也会生成 -Wstrict-overflow=3 警告?

问题描述 投票:0回答:2

根据

-Wstrict-overflow
的文档,3级:

还警告其他简化比较的情况。例如:x + 1 > 1 简化为 x > 0。

下面显示的 MWE 在级别 3 及以上(但不低于)时抛出以下警告,如果优化设置为 -O2 及以上但不低于,

AND
。 g++ 版本 9.3.0 和 10.2 展示了这一点。

$ g++ -O3 -Wall -Wextra -迂腐-std=c++17 -Wstrict-overflow=3 a.cpp
a.cpp:在函数“void std::push_heap(_RAIter, _RAIter) [with _RAIter = long unsigned int*]”中: a.cpp:8:1:警告:假设将 X +- C1 cmp C2 更改为 X cmp C2 -+ C1 [-Wstrict-overflow] 时不会发生有符号溢出

现场演示

MWE

#include <algorithm>

int main() {
  std::size_t v[] = {0,10,3};
  std::make_heap(std::begin(v),std::end(v));
  std::pop_heap(std::begin(v),std::end(v));
  std::push_heap(std::begin(v),std::end(v)); // <---
}

问题

  • 这是库实现中的错误吗?我没有看到任何任何签名类型。
  • 如何解决此问题,同时仍将
    -Wstrict-overflow
    保持在最高级别 5?
c++ g++ warnings std signed-overflow
2个回答
1
投票
  • 这是库实现中的错误吗?我没有看到任何签名类型。

不。库的实现是正确的。使用

-fsanitize=undefined
确认没有溢出。

警告仅告诉您编译器假设没有发生溢出。如果它假设代码没有未定义的行为,那么它可以更积极地优化代码,因此它假设代码没有溢出。该警告只是告诉您做出了这样的假设,因为如果您向函数提供实际上确实导致溢出的输入,则该假设可能是错误的。

所以警告的意思是“你最好不要在这里提供错误的输入,因为这会让这个优化产生不正确的结果”。

我报告了一个编译器错误(PR 96658),但严格来说,GCC 的行为符合文档。

  • 如何解决此问题,同时仍将 -Wstrict-overflow 保持在最大级别 5?

-Wstrict-overflow
的文档很清楚,它会给出误报,所以不要将它与
-Werror
结合起来,那太愚蠢了。


0
投票

-fsanitize=undefined 确认没有溢出。

这个说法是错误的。 (以逻辑学家的身份说话;-))

-fsanitize=xxx 通过运行时检查来检测代码。 当然,仅使用 -fsanitize=undefined 进行编译并不能提供有关潜在溢出的任何确认/确认。

如果您运行检测的代码,并且它中止或记录“UB:溢出”,那么您肯定可以说存在溢出。 如果没有出现错误,则仅意味着:

  • 要么根本不可能发生溢出
  • 或者您提供的输入没有触发溢出,但其他输入会触发溢出。

干杯!

© www.soinside.com 2019 - 2024. All rights reserved.