Unicorn with delicious cookie
Our website uses cookies to enhance your browsing experience.
Accept
to the top
>
>
>
V1083. Signed integer overflow in arith…
menu mobile close menu
Analyzer diagnostics
General Analysis (C++)
General Analysis (C#)
General Analysis (Java)
Micro-Optimizations (C++)
Diagnosis of 64-bit errors (Viva64, C++)
Customer specific requests (C++)
MISRA errors
AUTOSAR errors
OWASP errors (C++)
OWASP errors (C#)
OWASP errors (Java)
Problems related to code analyzer
Additional information
toggle menu Contents

V1083. Signed integer overflow in arithmetic expression. This leads to undefined behavior.

May 13 2022

The analyzer has detected an arithmetic expression where a signed integer overflow may occur.

The example:

long long foo()
{
  long longOperand = 0x7FFF'FFFF;
  long long y = longOperand * 0xFFFF;
  return y;
}

According to the C and C++ rules, the result type of the longOperand * 0xFFFF expression will be long. On Windows, when using the MSVC compiler, the long type is 4 bytes in size. The maximum value that can be represented by this type is 2'147'483'647 in decimal or 0x7FFF'FFFF in hexadecimal. When multiplying the longOperand variable by 0xFFFF (65,535), the 0x7FFF'7FFF'0001 result is expected. However, as specified in the C18 standard (section 6.5, paragraph 5) and C++20 (section 7.1, paragraph 4), the signed integer overflow leads to undefined behavior.

There are several ways to fix this code.

To evaluate expressions correctly, use types with a size large enough to hold the expected value. If the value does not fit a machine word, use one of the libraries for arbitrary-precision arithmetic, such as GMP, MPRF, and cnl.

The code fragment above can be fixed as follows:

long long foo()
{
  long longOperand = 0x7FFF'FFFF;
  long long y = static_cast<long long>(longOperand) * 0xFFFF;
  return y;
}

To handle the signed integer overflow as an unintended behavior, use specialized libraries that provide safe integer operations, such as boost::safe_numerics or Google Integers.

To implement wraparound arithmetic for signed integers with standard-defined behavior, use unsigned integers for evaluations. When the unsigned integer overflow occurs, the integer wraps around modulo 2 ^ n, where n is the number of bits within the integer.

The possible solution based on std::bit_cast (C++20):

#include <concepts>
#include <type_traits>
#include <bit>
#include <functional>

namespace detail
{
  template <std::signed_integral R,
            std::signed_integral T1,
            std::signed_integral T2,
            std::invocable<std::make_unsigned_t<T1>,
                           std::make_unsigned_t<T2>> Fn>
  R safe_signed_wrapper(T1 lhs, T2 rhs, Fn &&op)
    noexcept(std::is_nothrow_invocable_v<Fn,
                                         std::make_unsigned_t<T1>,
                                         std::make_unsigned_t<T2>>)
  {
    auto uLhs = std::bit_cast<std::make_unsigned_t<T1>>(lhs);
    auto uRhs = std::bit_cast<std::make_unsigned_t<T2>>(rhs);

    auto res = std::invoke(std::forward<Fn>(op), uLhs, uRhs);

    using UR = std::make_unsigned_t<R>;
    return std::bit_cast<R>(static_cast<UR>(res));
  }
}

The std::bit_cast function converts lhs and rhs to the corresponding unsigned representations. Next, some arithmetic operation is performed on the two converted operands. After that, the result is expanded or narrowed to the required result type and converted to a signed one.

With this approach, signed integers follow the semantics of unsigned ones in arithmetic operations. This does not lead to undefined behavior.

For example, you can see here that the compiler may optimize the code if it detects the signed integer overflow.

The example:

bool is_max_int(int32_t a)
{
  return a + 1 < a;
}

If a equals MAX_INT, the a + 1 < a condition will be false. This is a way to check whether an overflow has occurred. However, the compiler generates the following code:

is_max_int(int):                        # @is_max_int(int)
        xor     eax, eax
        ret

The assembly xor eax, eax instruction resets the result of the is_max_int function execution. As a result, the latter function always returns true, no matter what the a value has. In this case, this is the result of undefined behavior due to overflow.

In the case of an unsigned representation, undefined behavior does not occur:

is_max_int(int):                        # @is_max_int(int)
        cmp     edi, 2147483647
        sete    al
        ret

The compiler has generated code that does check the condition.

Note. The diagnostic rule supports a special setting that enables the analyzer to detect overflow in both signed and unsigned numeric types.

To enable this setting, add the following comment to the source code or to the diagnostic rules configuration file (.pvsconfig):

//+V1083 CHECK_UNSIGNED_OVERFLOW:YES

To disable the setting, add the comment:

//+V1083 CHECK_UNSIGNED_OVERFLOW:NO

This diagnostic is classified as:

You can look at examples of errors detected by the V1083 diagnostic.

close form

Fill out the form in 2 simple steps below:

Your contact information:

Step 1
Congratulations! This is your promo code!

Desired license type:

Step 2
Team license
Enterprise license
** By clicking this button you agree to our Privacy Policy statement
close form
Request our prices
New License
License Renewal
--Select currency--
USD
EUR
* By clicking this button you agree to our Privacy Policy statement

close form
Free PVS‑Studio license for Microsoft MVP specialists
* By clicking this button you agree to our Privacy Policy statement

close form
To get the licence for your open-source project, please fill out this form
* By clicking this button you agree to our Privacy Policy statement

close form
I want to join the test
* By clicking this button you agree to our Privacy Policy statement

close form
check circle
Message submitted.

Your message has been sent. We will email you at


If you do not see the email in your inbox, please check if it is filtered to one of the following folders:

  • Promotion
  • Updates
  • Spam