1 2 /* This test case was originally written by Nicholas Nethercote. */ 3 4 // [[This comment applies to the old piggybacking approach to 5 // origin-tracking. The newer approach handles the cases in this file 6 // correctly.]] 7 // This test demonstrates cases the piggybacking algorithm cannot handle, 8 // but which are handled ok by the instrumentation based algorithm. 9 10 #include <assert.h> 11 #include <stdlib.h> 12 #include <stdio.h> 13 #include "../memcheck.h" 14 15 int x = 0; 16 17 __attribute__((noinline)) int t1(void); 18 __attribute__((noinline)) int t2(void); 19 __attribute__((noinline)) int t3(void); 20 __attribute__((noinline)) int t4(void); 21 __attribute__((noinline)) int t5(void); 22 __attribute__((noinline)) int t6(void); 23 24 int main(void) 25 { 26 assert(4 == sizeof(int)); 27 28 x += t1(); 29 x += t2(); 30 x += t3(); 31 x += t4(); 32 x += t5(); 33 x += t6(); 34 35 return x & 255; 36 } 37 38 __attribute__((noinline)) int t1(void) 39 { 40 // 8-bit undefined value. When compared it's loaded from memory, so will 41 // never work. 42 char* ptr_to_undef_char = malloc(sizeof(char)); 43 char undef_char = *ptr_to_undef_char; 44 fprintf(stderr, "\nUndef 1 of 8 (8 bit undef)\n"); 45 return (undef_char == 0x12 ? 11 : 22); 46 } 47 48 __attribute__((noinline)) int t2(void) 49 { 50 // Stack, 8-bit from (recently) 32-bit. But the load only loads 8-bits 51 // of the value, so it'll never work. 52 int undef_stack_int; 53 register char undef_stack_char = (char)undef_stack_int; 54 fprintf(stderr, "\nUndef 2 of 8 (8 bits of 32 undef)\n"); 55 return (undef_stack_char == 0x12 ? 11 : 22); 56 } 57 58 __attribute__((noinline)) int t3(void) 59 { 60 // 32-bit undefined value. This one is identified, and is here for 61 // sanity-checking. 62 int* ptr_to_undef_int = malloc(sizeof(int)); 63 int undef_int = *ptr_to_undef_int; 64 fprintf(stderr, "\nUndef 3 of 8 (32 bit undef)\n"); 65 return (undef_int == 0x12345678 ? 13 : 24); 66 } 67 68 __attribute__((noinline)) int t4(void) 69 { 70 // Unaligned 32-bit value. 71 int* ptr_to_undef_int = malloc(sizeof(int) + 1); 72 int undef_unaligned_int = *(int*)((long)ptr_to_undef_int + 1); 73 fprintf(stderr, "\nUndef 4 of 8 (32 bit undef, unaligned)\n"); 74 return (undef_unaligned_int == 0x12345678 ? 14 : 25); 75 } 76 77 __attribute__((noinline)) int t5(void) 78 { 79 // Modified 32-bit value. 80 int* ptr_to_undef_int3 = malloc(sizeof(int)); 81 int modified_undef_int = *ptr_to_undef_int3; 82 fprintf(stderr, "\nUndef 5 of 8 (32 bit undef, modified)\n"); 83 modified_undef_int++; 84 return (modified_undef_int == 0x12345678 ? 15 : 26); 85 } 86 87 __attribute__((noinline)) int t6(void) 88 { 89 int y = 0; 90 91 // Uninitialised 32-bit value (middle of 3) is made undefined in two 92 // unaligned pieces: 93 // |....|....|....| three 4-byte integers 94 // XXXX-YY first MAKE_MEM_UNDEFINED 95 // YY-XXXX second MAKE_MEM_UNDEFINED 96 // Because the YY parts don't get marked (they're not 32-bit and aligned) 97 // the middle byte keeps its original value, which is zero (from calloc). 98 // So even though it's been marked as undefined, it doesn't have an 99 // origin-tracking value and so cannot be identified. We also check the 100 // first and third ints (which are identified) for sanity-checking. 101 { 102 int* ptr_to_3_undef_ints = calloc(3, sizeof(int)); 103 int* ptr_to_middle = (int*)((long)ptr_to_3_undef_ints + 6); 104 (void) VALGRIND_MAKE_MEM_UNDEFINED(ptr_to_3_undef_ints, 6); 105 (void) VALGRIND_MAKE_MEM_UNDEFINED(ptr_to_middle, 6); 106 fprintf(stderr, "\nUndef 6 of 8 (32 bit undef, unaligned, strange, #1)\n"); 107 y += (*(ptr_to_3_undef_ints + 0) == 0x12345678 ? 16 : 27); 108 fprintf(stderr, "\nUndef 7 of 8 (32 bit undef, unaligned, strange, #2)\n"); 109 y += (*(ptr_to_3_undef_ints + 1) == 0x12345678 ? 17 : 28); 110 fprintf(stderr, "\nUndef 8 of 8 (32 bit undef, unaligned, strange, #3)\n"); 111 y += (*(ptr_to_3_undef_ints + 2) == 0x12345678 ? 18 : 29); 112 return y; 113 } 114 115 return x; 116 } 117