代码之家  ›  专栏  ›  技术社区  ›  The Quantum Physicist

优化正在终止我在Clang6中的整数溢出检查

  •  4
  • The Quantum Physicist  · 技术社区  · 7 年前

    N 作为十进制数处理。这个类是偏执的,会检查溢出,但是当我在发布模式下运行测试时,它们失败了,最后我创建了这个演示问题的最小示例:

    #include <iostream>
    #include <sstream>
    
    template <typename T, typename U>
    typename std::enable_if<std::is_convertible<U, std::string>::value, T>::type 
    FromString(U&& str)
    {
        std::stringstream ss;
        ss << str;
        T ret;
        ss >> ret;
        return ret;
    }
    
    int main()
    {
        int NewAccu=32;
        int N=10;
    
        using T = int64_t;
    
        T l = 10;
        T r = FromString<T>("1" + std::string(NewAccu - N, '0'));
        if (l == 0 || r == 0) {
            return 0;
        }
        T res = l * r;
        std::cout << l << std::endl;
        std::cout << r << std::endl;
        std::cout << res << std::endl;
        std::cout << (res / l) << std::endl;
        std::cout << std::endl;
        if ((res / l) != r) {
            throw std::runtime_error(
                       "FixedPoint Multiplication Overflow while upscaling [:" + std::to_string(l) + ", " + std::to_string(r) + "]");
        }
    
        return 0;
    }
    

    这发生在Clang 6中,我的版本是:

    $ clang++ --version
    clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
    Target: x86_64-pc-linux-gnu
    Thread model: posix
    InstalledDir: /usr/bin
    

    这很有趣,因为这是一个令人印象深刻的优化,但这会破坏我的应用程序,并阻止我检测溢出。我能重现这个问题 in g++ here

    请注意,异常是在调试模式下抛出的,但不是在发布模式下抛出的。

    2 回复  |  直到 7 年前
        1
  •  9
  •   plasmacel example    7 年前

    作为 @罗勒 如上所述,有符号整数溢出是 未定义的行为 ,因此编译器可以以任何方式处理它—甚至可以优化它以获得性能优势。所以呢 检测 预测 整数溢出就在它发生之前。

    下面是我对整数乘法溢出预测的实现:

    #include <limits>
    
    template <typename T>
    bool predict_mul_overflow(T x, T y)
    {
        static_assert(std::numeric_limits<T>::is_integer, "predict_mul_overflow expects integral types");
    
        if constexpr (std::numeric_limits<T>::is_bounded)
        {
            return ((x != T{0}) && ((std::numeric_limits<T>::max() / x) < y));
        }
        else
        {
            return false;
        }
    }
    

    函数返回 true 如果整数乘法 x * y 预计将溢出。

    请注意 unsigned modular arithmetic signed 溢出是一种 undefined behavior . 然而,所呈现的函数适用于 签署 未签名 T

        2
  •  4
  •   Basile Starynkevitch    7 年前

    如果要检测(已签名) integer overflows (对于标量类型,如 int64_t long

    有关GCC,请参阅 integer overflow builtins

    整数溢出(普通) int 长的 或其他有符号整数类型)的实例 undefined behavior ,因此编译器可以根据需要对其进行优化。是 scared . 如果你依赖于UB,你就不再需要在标准C++中编码,而且程序绑定到一个特定的编译器和系统,所以不是。 portable 完全没有(甚至对其他编译器、其他编译器版本、其他编译标志、其他计算机和操作系统)。因此,Clang(或GCC)可以针对整数溢出进行优化,有时也可以。

    或者考虑使用一些 bignum 包(当然,你不需要处理预定义的C++积分标量类型)。也许 GMPlib .

    __int128

    我相信当整数溢出发生时,您无法可靠地检测到它们(除非您使用 整数溢出内置 ). 您应该避免使用它们(或者使用一些bignum库,或者使用这些内置函数的库,等等)。