| |
| /* This test case was originally written by Nicholas Nethercote. */ |
| |
| // This test demonstrates some cases that the piggybacking algorithm |
| // doesn't handle but conceivably might, with more modifications. |
| // The instrumentation based algorithm handles them ok, though. |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| int x = 0; |
| |
| typedef long long Long; |
| |
| __attribute__((noinline)) int t1(void); |
| __attribute__((noinline)) int t2(void); |
| __attribute__((noinline)) int t3(void); |
| |
| int main(void) |
| { |
| assert(4 == sizeof(int)); |
| assert(8 == sizeof(Long)); |
| |
| x += t1(); |
| x += t2(); |
| x += t3(); |
| |
| return x & 255; |
| } |
| |
| __attribute__((noinline)) int t1(void) |
| { |
| // 64-bit undefined double. |
| double* ptr_to_undef_double = malloc(sizeof(double)); |
| double undef_double = *ptr_to_undef_double; |
| fprintf(stderr, "\nUndef 1 of 3 (64-bit FP)\n"); |
| return (undef_double < (double)123.45 ? 12 : 23); |
| } |
| |
| __attribute__((noinline)) int t2(void) |
| { |
| // 32-bit undefined float. |
| float* ptr_to_undef_float = malloc(sizeof(float)); |
| float undef_float = *ptr_to_undef_float; |
| fprintf(stderr, "\nUndef 2 of 3 (32-bit FP)\n"); |
| return (undef_float < (float)234.56 ? 13 : 24); |
| } |
| |
| __attribute__((noinline)) int t3(void) |
| { |
| // Stack, 32-bit, recently modified. |
| // Problem here is that we don't chase backwards through loads and |
| // stores. Ie. the variable is stored after it's been modified, then |
| // loaded again, so we don't see the unmodified version. |
| int modified_undef_stack_int; |
| modified_undef_stack_int++; |
| fprintf(stderr, "\nUndef 3 of 3 (int)\n"); |
| return (modified_undef_stack_int == 0x1234 ? 11 : 22); |
| } |