-fsanitize=integer improvements?

I was excited to find out about this feature and trying it out on my code.

The first problem was that I had been using -1U instead of UINT_MAX a lot. I think it's pretty obvious that -1U is meant as UINT_MAX instead of overflowing the integer. Anyway, I switched them to UINT_MAX so this isn't really an issue.

The main problem is with code like:

  unsigned int foo = 1000; // always a positive number
  int diff = -1; // positive or negative number that doesn't overflow/underflow foo

  printf("%u\n", foo + diff);

Because diff gets translated to UINT_MAX here, which then overflows the calculation. Couldn't these type of calculations somehow be skipped over? Or alternatively could the compiler give a warning when it's mixing up signed and unsigned integer calculations so these could at least be found easily at compile stage?

I see someone else already asked about disabling the checks for some specific calculations. Will Dietz replied about planning to soon add "safe attributes" to do that. Is this implemented yet? Or can I use some #pragma to remove the checks from md5/sha code files (I'd rather not want to mess with automake for this). I was also wondering about the possibility of doing this in a somewhat standard way by explicitly using modulo on the result, such as:

printf("%u\n", (UINT_MAX + 5) % UINT_MAX);

or even any modulo:

printf("%u\n", (UINT_MAX + 5) % 2);

I think these make it clear that modulo arithmetic is intended and an overflow can't be a bug.

I was excited to find out about this feature and trying it out on my code.

The first problem was that I had been using -1U instead of UINT_MAX a lot. I think it’s pretty obvious that -1U is meant as UINT_MAX instead of overflowing the integer. Anyway, I switched them to UINT_MAX so this isn’t really an issue.

The main problem is with code like:

unsigned int foo = 1000; // always a positive number
int diff = -1; // positive or negative number that doesn’t overflow/underflow foo

printf("%u\n", foo + diff);

Because diff gets translated to UINT_MAX here, which then overflows the calculation. Couldn’t these type of calculations somehow be skipped over? Or alternatively could the compiler give a warning when it’s mixing up signed and unsigned integer calculations so these could at least be found easily at compile stage?

Well, the problem with such a warning is that the code is perfectly Standard compliant and the behavior is very precisely dictated by the Standard; as such there is a probably LOT of code that has been written this way (mind you, with positive values of diff) and works like a charm, developers on this code are unlikely to be willing to see warnings on this… and Clang’s rule of thumb for warnings is that if it cannot be on by default, then it’s probably not worth it.

I see someone else already asked about disabling the checks for some specific calculations. Will Dietz replied about planning to soon add “safe attributes” to do that. Is this implemented yet?

The discussion is still on as to the syntax, the agreement should come soon though. Of course, no planned date for the change then landing.

Or can I use some #pragma to remove the checks from md5/sha code files (I’d rather not want to mess with automake for this). I was also wondering about the possibility of doing this in a somewhat standard way by explicitly using modulo on the result, such as:

printf("%u\n", (UINT_MAX + 5) % UINT_MAX);

or even any modulo:

printf("%u\n", (UINT_MAX + 5) % 2);

I think these make it clear that modulo arithmetic is intended and an overflow can’t be a bug.

I am actually surprised that there is a trap on overflow on unsigned types, where it’s perfectly defined.

– Matthieu

You can enable such a warning with '-Wsign-conversion'. Using -Weverything is a handy way to discover what warnings are available. Here's the warning generated by your code:

main.cpp:7:23: warning: implicit conversion changes signedness: 'int' to 'unsigned int' [-Wsign-conversion]
        printf("%u\n", foo + diff);
                           ~ ^~~~