How to obtain warning for forgotten cast in arithmetic?

前端 未结 3 1606
悲哀的现实
悲哀的现实 2021-01-13 13:01

Consider this situation:

uint64_t add(uint32_t a, uint32_t b)
{
   return a + b; // programmer neglected (uint64_t) a + b.
}

How do we get

3条回答
  •  粉色の甜心
    2021-01-13 13:38

    Visual Studio Code Analysis can do that

    It has various checks for integer overflow including unsigned operations

    • C26450 RESULT_OF_ARITHMETIC_OPERATION_PROVABLY_LOSSY: [operator] operation causes overflow at compile time. Use a wider type to store the operands. This warning indicates that an arithmetic operation was provably lossy at compile time. This can be asserted when the operands are all compile-time constants. Currently, we check left shift, multiplication, addition, and subtraction operations for such overflows.

      uint32_t multiply()
      {
         const uint32_t a = UINT_MAX; // the author used int here 
         const uint32_t b = 2;        // but I changed to unsigned for this question
         uint32_t c = a * b; // C26450 reported here [and also C4307]
         return c;
      }
      
    • C26451 RESULT_OF_ARITHMETIC_OPERATION_CAST_TO_LARGER_SIZE: Using operator [operator] on a [size1] byte value and then casting the result to a [size2] byte value. Cast the value to the wider type before calling operator [operator] to avoid overflow.

      This warning indicates incorrect behavior that results from integral promotion rules and types larger than those in which arithmetic is typically performed. We detect when a narrow type integral value was shifted left, multiplied, added, or subtracted and the result of that arithmetic operation was cast to a wider type value. If the operation overflowed the narrow type value, then data is lost. You can prevent this loss by casting the value to a wider type before the arithmetic operation.

      void leftshift(int i) {
         unsigned long long x;
         x = i << 31; // C26451 reported here
              // code
      
      // Corrected source:
      void leftshift(int i) {
          unsigned long long x;
          x = (unsigned long long)i << 31; // OK
              // code
      }
      
    • C26454 RESULT_OF_ARITHMETIC_OPERATION_NEGATIVE_UNSIGNED: [operator] operation wraps past 0 and produces a large unsigned number at compile time

      This warning indicates that the subtraction operation produces a negative result which was evaluated in an unsigned context. This causes the result to wrap past 0 and produce a really large unsigned number, which can result in unintended overflows.

      // Example source:
      unsigned int negativeunsigned() {
          const unsigned int x = 1u - 2u; // C26454 reported here
          return x;
      }
      
      // Corrected source:
      unsigned int negativeunsigned() {
          const unsigned int x = 4294967295; // OK
          return x;
      }
      

    Arithmetic overflow checks in C++ Core Check

    Here's an example of it in action

    As you can see from the examples above, the compiler itself can also emit a warning if the operands were compile time constants. If they were variables then you need the static analyzer

    You can play around with that on Compiler Explorer, although I'm not sure how to make it really work from command line. If you know how to pass arguments to VS code analysis please comment below. On MSVC GUI just press Alt+F11

    For information on how to run the analysis read C++ Static Analysis Improvements for Visual Studio 2017 15.6 Preview 2


    Clang doesn't have a compile-time option for that, but it has an option to check at runtime

    -fsanitize=unsigned-integer-overflow: Unsigned integer overflow, where the result of an unsigned integer computation cannot be represented in its type. Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. This sanitizer does not check for lossy implicit conversions performed before such a computation (see -fsanitize=implicit-conversion).

    UndefinedBehaviorSanitizer

    It can also be disabled easily

    Silencing Unsigned Integer Overflow

    To silence reports from unsigned integer overflow, you can set UBSAN_OPTIONS=silence_unsigned_overflow=1. This feature, combined with -fsanitize-recover=unsigned-integer-overflow, is particularly useful for providing fuzzing signal without blowing up logs.

    Unfortunately GCC only supports -fsanitize=signed-integer-overflow. There's no unsigned version

提交回复
热议问题