" work correctly with size_t overflow? I am working on a project to update 20 year old code and many of the problems are wi...">

Operators "<" and ">" work correctly with size_t overflow?

I am working on a project to update 20 year old code and many of the problems are with integer overflow. I wanted to make sure I tested the overflow correctly, so I wrote a test program. He betrayed me. Here he is:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>

int main (void) {

   size_t largerNum,Num;

   largerNum = 12;
   Num = UINT_MAX;

   printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum    , Num, Num + 1);

   largerNum = Num + 1;

   printf("largerNum now = %u\n", largerNum);

   if(largerNum < Num ){
      printf("largerNum overflowed to %u\n", largerNum);
   }
   else {
      printf("largerNum did not overflow: %u\n", largerNum);
   }

   printf("Is (0 < UINT_MAX)?\n");

   (0 < UINT_MAX)?printf("YES\n"):printf("NO\n");

   printf("Is (largerNum < Num)?\n");

   (largerNum < Num)?printf("YES\n"):printf("NO\n");

   return 0;
}

      

And its output:

[[email protected] /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 0
largerNum did not overflow: 0
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
NO

      

I looked at other posts here and here and read this paper , but it didn't make the conclusion clearer. Has anyone seen this before?

Edit: I got it to work when changing from size_t

to unsigned long

, which shouldn't do anything.

  6 int main (void) {
  7 
  8    unsigned long largerNum,Num;
  9 
 10    largerNum = 12;
 11    Num = UINT_MAX;
 12 
 13    printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum    , Num, Num + 1);
 14 
 15    largerNum = Num + 2;
 16 
 17    printf("largerNum now = %u\n", largerNum);
 18 
 19    if(largerNum < Num ){
 20       printf("largerNum overflowed to %u\n", largerNum);
 21    }
 22    else {
 23       printf("largerNum did not overflow: %u\n", largerNum);
 24    }
 25 
 26    printf("Is (0 < UINT_MAX)?\n");
 27 
 28    (0 < UINT_MAX)?printf("YES\n"):printf("NO\n");
 29 
 30    printf("Is (largerNum < Num)?\n");
 31 
 32    (largerNum < Num)?printf("YES\n"):printf("NO\n");
 33 
 34 
 35    printf("largerNum = %u\n", largerNum);
 36    printf("Num = %u\n", Num);
 37 
 38    return 0;
 39 }

      

Output:

[[email protected] /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 4294967295

      

Edit2:

While reading some comments, I replaced 'UINT_MAX' with 'ULONG_MAX' and the ternary operators worked correctly. Then I changed 'size_t' to 'unsigned long'. and it still works correctly. What's strange to me is that on my machine "size_t", "unsigned int" and "unsigned long" are the same number of bytes, and "UINT_MAX" and "ULONG_MAX" are the same value, but this ternary operator will still fail even though everything stays the same. Maybe it's not the same? This frustrates my understanding of C.

For those interested, working code:

  6 int main (void) {
  7    /* Can be size_t or unsigned long */
  8    size_t largerNum,Num;
  9 
 10    largerNum = 12;
 11    Num = ULONG_MAX;
 12 
 13    printf("largerNum = %u\nNum = %u\nNum + 1 = %u\n", largerNum    , Num, Num + 1);
 14 
 15    largerNum = Num + 2;
 16 
 17    printf("largerNum now = %u\n", largerNum);
 18 
 19    if(largerNum < Num ){
 20       printf("largerNum overflowed to %u\n", largerNum);
 21    }
 22    else {
 23       printf("largerNum did not overflow: %u\n", largerNum);
 24    }
 25 
 26    printf("Is (0 < ULONG_MAX)?\n");
 27 
 28    (0 < ULONG_MAX)?printf("YES\n"):printf("NO\n");
 29 
 30    printf("Is (largerNum < Num)?\n");
 31 
 32    (largerNum < Num)?printf("YES\n"):printf("NO\n");
 33 
 34    
 35    printf("largerNum = %u\n", largerNum);
 36    printf("Num = %u\n", Num);
 37    
 38    return 0;
 39 }

      

Output:

[[email protected] /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 4294967295
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < ULONG_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 4294967295

      

Final Edit:

After reading more comments, I found my instructions printf()

were wrong. Thanks everyone for your help and now everything makes sense. = D

Final code:

  6 int main (void) {
  7 
  8    unsigned long largerNum,Num;
  9 
 10    largerNum = 12;
 11    Num = ULONG_MAX;
 12 
 13    printf("largerNum = %zu\nNum = %zu\nNum + 1 = %zu\n", larger    Num, Num, Num + 1);
 14 
 15    largerNum = Num + 2;
 16 
 17    printf("largerNum now = %zu\n", largerNum);
 18 
 19    if(largerNum < Num ){
 20       printf("largerNum overflowed to %zu\n", largerNum);
 21    }
 22    else {
 23       printf("largerNum did not overflow: %zu\n", largerNum);
 24    }
 25 
 26    printf("Is (0 < ULONG_MAX)?\n");
 27 
 28    (0 < ULONG_MAX)?printf("YES\n"):printf("NO\n");
 29 
 30    printf("Is (largerNum < Num)?\n");
 31 
 32    (largerNum < Num)?printf("YES\n"):printf("NO\n");
 33 
 34 
 35    printf("largerNum = %zu\n", largerNum);
 36    printf("Num = %zu\n", Num);
 37 
 38    return 0;
 39 }

      

Final result:

[[email protected] /home/afischer/Fischer_Playground/overflowTest]$ main
largerNum = 12
Num = 18446744073709551615
Num + 1 = 0
largerNum now = 1
largerNum overflowed to 1
Is (0 < ULONG_MAX)?
YES
Is (largerNum < Num)?
YES
largerNum = 1
Num = 18446744073709551615

      

+3


source share


2 answers


I am assuming your platform is 64-bit size_t

and you are using the wrong format specifier for printing size_t

, which has undefined behavior and leads to erroneous output.

In print size_t

s
use %zu

in gcc and clang and %Iu

in MSVC. Or forget it all and use it std::cout

to print the results.



Using %Iu

on VS2015, the output I get in the 64 bit compiler is

largerNum = 12
Num = 4294967295
Num + 1 = 4294967296
largerNum now = 4294967296
largerNum did not overflow: 4294967296
Is (0 < UINT_MAX)?
YES
Is (largerNum < Num)?
NO

      

+7


source


Just by adding to @ Praetorian's answer and showing a type safe implementation:

#include <iostream>
#include <limits>

int main (void) {
   using std::size_t;
   using std::cout;

   size_t largerNum = 12;
   size_t Num = std::numeric_limits<size_t>::max();

   cout << "largerNum = " << largerNum << "\nNum = " << Num << "\nNum + 1 = " << Num + 1 << "\n";
   largerNum = Num + 1;
   cout << "largerNum now = " << largerNum << "\n";

   if(largerNum < Num ){
       cout << "largerNum overflowed to " << largerNum << "\n";
   }
   else {
       cout << "largerNum did not overflow: " << largerNum << "\n";
   }

   cout << "Is (0 < Unsigned Maximum)?\n";

   (0 < std::numeric_limits<size_t>::max())?cout << "YES\n":cout << "NO\n";

   cout << "Is (largerNum < Num)?\n";

   (largerNum < Num)?cout << "YES\n":cout << "NO\n";

   return 0;
}

      



Hence: 'printf' is not a good choice in C ++, it is not type safe (although good compilers may recognize invalid format specifiers). On the other hand, iostream operators are cumbersome (for many) and bad if the output needs to be translated into different languages ​​(ex: gnu getline). You can browse the net for a format-safe type string (ex: boost: format)

+1


source







All Articles