Skip to content

addc compiler bug on some MSVC versions when constant evaluated. #369

Description

@Marcus10110

This isn't technically a bug in intx. This issue is caused by a bug in the MSVC compiler, and seems to be fixed in very recent versions of MSVC. IMO it would be worth fixing in intx, but not required. This is still a useful FYI to anyone else who runs into this.

On MSVC, intx::addc(uint64_t, uint64_t, bool) returns carry == false when it should return true, if both operands are compile-time constants and optimizations are on.

auto r = intx::addc(0xFFFF'FFFF'FFFF'FFFFull, 1ull, false);
// expected: r.value == 0, r.carry == true
// actual (/O1, /O2, /O2 /GL): r.value == 0, r.carry == false
// without optimizations, output is correct.

This bug ultimately flows through to cause more serious issues like this:
uint128(2^64 - 1) + 1 returning 0 instead of 2^64.

Originally reproduced on MSVC 19.40.33812 (VS 2022 Community). Using godbolt.org, (https://godbolt.org/z/514rxdor9) you can check which compiler versions & optimization flags have the error, and which don't.

Looks like x64 MSVC 19.44 and newer works correctly, and arm64 MSVC 19.50 and newer works correctly.

Our fix was to replace return {t, carry1 || carry2} with return {t, static_cast<bool>( carry1 | carry2 )} in addc and replace return {e, carry1 || carry2} with return {e, static_cast<bool>( carry1 | carry2 )} in subc.

I didn't exhaustively check the rest of intx for similar issues. I came across this while migrating off of boost multiprecision.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions