Skip to content

Instantly share code, notes, and snippets.

@antirez
Created February 21, 2012 14:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antirez/1876875 to your computer and use it in GitHub Desktop.
Save antirez/1876875 to your computer and use it in GitHub Desktop.
/* If you compile with -O2 the code will print "Wrong behavior", compiling
* with -O0 the code will print "Correct behavior".
*
* Tested with:
* Apple clang version 2.1 (tags/Apple/clang-163.7.1) (based on LLVM 3.0svn)
* Target: x86_64-apple-darwin11.3.0
* Thread model: posix
*/
#include <stdio.h>
int getValue(long long *l) {
*l = -9223372036854775484LL;
return 1;
}
void bug(void) {
long long value, incr, oldvalue;
incr = -1000;
if (getValue(&value) != 1) return;
oldvalue = value;
value += incr;
if ((incr < 0 && value > oldvalue) || (incr > 0 && value < oldvalue)) {
printf("Correct behavior\n");
} else {
printf("Wrong behavior\n");
}
}
int main(void) {
bug();
}
@asl
Copy link

asl commented Feb 21, 2012

@malu: this is not always possible. Consider e.g. here the function getValue() to be external (and not visible to compiler). The UB in line 24 may or may not be depending on the value returned. -ftrapv will add the checks for some cases of UB, so, it can be caught in the runtime.

@malu
Copy link

malu commented Feb 21, 2012

Okay, I didn't think of external function, that'd be a problem.

@antirez
Copy link
Author

antirez commented Feb 21, 2012

Related: /usr/include/i386/limits.h:#define LLONG_MIN (-0x7fffffffffffffffLL-1)

@antirez
Copy link
Author

antirez commented Feb 21, 2012

I'm turning the old code into this one:

    oldvalue = value;
    if ((incr < 0 && oldvalue < 0 && incr < (LLONG_MIN-oldvalue)) ||
        (incr > 0 && oldvalue > 0 && incr > (LLONG_MAX-oldvalue))) {
        printf("Correct behavior\n");
    } else {
        printf("Wrong behavior\n");
    }
    value += incr;

Should be safe since it is guaranteed that all the parts never overflow.
LLONG_MIN-oldvalue can't overflow because oldvalue is guaranteed to be < 0
LLONG_MAX-oldvalue can't overflow because oldvalue is guaranteed to be > 0

Now trying it in practice :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment