1 #define _GNU_SOURCE 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include "../memcheck.h" 6 #include "leak.h" 7 #include <sys/mman.h> 8 #include <sys/syscall.h> 9 10 typedef unsigned long UWord; 11 typedef unsigned long long int ULong; 12 // Below code is copied from m_syscall.c 13 // Refer to this file for syscall convention. 14 #if defined(VGP_x86_linux) 15 extern UWord do_syscall_WRK (UWord syscall_no, 16 UWord a1, UWord a2, UWord a3, 17 UWord a4, UWord a5, UWord a6 18 ); 19 asm( 20 ".text\n" 21 ".globl do_syscall_WRK\n" 22 "do_syscall_WRK:\n" 23 " push %esi\n" 24 " push %edi\n" 25 " push %ebx\n" 26 " push %ebp\n" 27 " movl 16+ 4(%esp),%eax\n" 28 " movl 16+ 8(%esp),%ebx\n" 29 " movl 16+12(%esp),%ecx\n" 30 " movl 16+16(%esp),%edx\n" 31 " movl 16+20(%esp),%esi\n" 32 " movl 16+24(%esp),%edi\n" 33 " movl 16+28(%esp),%ebp\n" 34 " int $0x80\n" 35 " popl %ebp\n" 36 " popl %ebx\n" 37 " popl %edi\n" 38 " popl %esi\n" 39 " ret\n" 40 ".previous\n" 41 ); 42 #elif defined(VGP_amd64_linux) 43 extern UWord do_syscall_WRK ( 44 UWord syscall_no, 45 UWord a1, UWord a2, UWord a3, 46 UWord a4, UWord a5, UWord a6 47 ); 48 asm( 49 ".text\n" 50 ".globl do_syscall_WRK\n" 51 "do_syscall_WRK:\n" 52 " movq %rdi, %rax\n" 53 " movq %rsi, %rdi\n" 54 " movq %rdx, %rsi\n" 55 " movq %rcx, %rdx\n" 56 " movq %r8, %r10\n" 57 " movq %r9, %r8\n" 58 " movq 8(%rsp), %r9\n" /* last arg from stack */ 59 " syscall\n" 60 " ret\n" 61 ".previous\n" 62 ); 63 64 #elif defined(VGP_ppc32_linux) 65 extern ULong do_syscall_WRK ( 66 UWord syscall_no, 67 UWord a1, UWord a2, UWord a3, 68 UWord a4, UWord a5, UWord a6 69 ); 70 asm( 71 ".text\n" 72 ".globl do_syscall_WRK\n" 73 "do_syscall_WRK:\n" 74 " mr 0,3\n" 75 " mr 3,4\n" 76 " mr 4,5\n" 77 " mr 5,6\n" 78 " mr 6,7\n" 79 " mr 7,8\n" 80 " mr 8,9\n" 81 " sc\n" /* syscall: sets %cr0.so on error */ 82 " mfcr 4\n" /* %cr -> low word of return var */ 83 " rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */ 84 " blr\n" /* and return */ 85 ".previous\n" 86 ); 87 88 #elif defined(VGP_arm_linux) 89 extern UWord do_syscall_WRK ( 90 UWord a1, UWord a2, UWord a3, 91 UWord a4, UWord a5, UWord a6, 92 UWord syscall_no 93 ); 94 asm( 95 ".text\n" 96 ".globl do_syscall_WRK\n" 97 "do_syscall_WRK:\n" 98 " push {r4, r5, r7}\n" 99 " ldr r4, [sp, #12]\n" 100 " ldr r5, [sp, #16]\n" 101 " ldr r7, [sp, #20]\n" 102 " svc 0x0\n" 103 " pop {r4, r5, r7}\n" 104 " bx lr\n" 105 ".previous\n" 106 ); 107 #elif defined(VGP_s390x_linux) 108 UWord do_syscall_WRK ( 109 UWord syscall_no, 110 UWord arg1, UWord arg2, UWord arg3, 111 UWord arg4, UWord arg5, UWord arg6 112 ) 113 { 114 register UWord __arg1 asm("2") = arg1; 115 register UWord __arg2 asm("3") = arg2; 116 register UWord __arg3 asm("4") = arg3; 117 register UWord __arg4 asm("5") = arg4; 118 register UWord __arg5 asm("6") = arg5; 119 register UWord __arg6 asm("7") = arg6; 120 register ULong __svcres asm("2"); 121 122 __asm__ __volatile__ ( 123 "lgr %%r1,%1\n\t" 124 "svc 0\n\t" 125 : "=d" (__svcres) 126 : "a" (syscall_no), 127 "0" (__arg1), 128 "d" (__arg2), 129 "d" (__arg3), 130 "d" (__arg4), 131 "d" (__arg5), 132 "d" (__arg6) 133 : "1", "cc", "memory"); 134 135 return (UWord) (__svcres); 136 } 137 138 #elif defined(VGP_mips64_linux) 139 extern UWord do_syscall_WRK ( 140 UWord syscall_no, 141 UWord a1, UWord a2, UWord a3, 142 UWord a4, UWord a5, UWord a6 143 ) 144 { 145 UWord out; 146 __asm__ __volatile__ ( 147 "move $v0, %1\n\t" 148 "move $a0, %2\n\t" 149 "move $a1, %3\n\t" 150 "move $a2, %4\n\t" 151 "move $a3, %5\n\t" 152 "move $8, %6\n\t" /* We use numbers because some compilers */ 153 "move $9, %7\n\t" /* don't recognize $a4 and $a5 */ 154 "syscall\n" 155 "move %0, $v0\n\t" 156 : /*out*/ "=r" (out) 157 : "r"(syscall_no), "r"(a1), "r"(a2), "r"(a3), 158 "r"(a4), "r"(a5), "r"(a6) 159 : "v0", "v1", "a0", "a1", "a2", "a3", "$8", "$9"); 160 return out; 161 } 162 #elif defined(VGP_tilegx_linux) 163 extern UWord do_syscall_WRK ( 164 UWord syscall_no, 165 UWord a1, UWord a2, UWord a3, 166 UWord a4, UWord a5, UWord a6 167 ) 168 { 169 UWord out; 170 __asm__ __volatile__ ( 171 "move r10, %1\n\t" 172 "move r0, %2\n\t" 173 "move r1, %3\n\t" 174 "move r2, %4\n\t" 175 "move r3, %5\n\t" 176 "move r4, %6\n\t" 177 "move r5, %7\n\t" 178 "swint1 \n\t" 179 "move %0, r0\n\t" 180 : /*out*/ "=r" (out) 181 : "r"(syscall_no), "r"(a1), "r"(a2), "r"(a3), 182 "r"(a4), "r"(a5), "r"(a6) 183 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r10"); 184 return out; 185 } 186 187 #else 188 // Ensure the file compiles even if the syscall nr is not defined. 189 #ifndef __NR_mprotect 190 #define __NR_mprotect 0 191 #endif 192 UWord do_syscall_WRK (UWord syscall_no, 193 UWord a1, UWord a2, UWord a3, 194 UWord a4, UWord a5, UWord a6 195 ) 196 { 197 // not implemented. vgtest prereq should avoid this to be called. 198 return -1; 199 } 200 #endif 201 202 203 204 char **b10; 205 int mprotect_result = 0; 206 static void non_simd_mprotect (long tid, void* addr, long len) 207 { 208 mprotect_result = do_syscall_WRK(__NR_mprotect, 209 (UWord) addr, len, PROT_NONE, 210 0, 0, 0); 211 } 212 213 void f(void) 214 { 215 long pagesize; 216 #define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1)) 217 int i; 218 const int nr_ptr = (10000 * 4)/sizeof(char*); 219 220 b10 = calloc (nr_ptr * sizeof(char*), 1); 221 for (i = 0; i < nr_ptr; i++) 222 b10[i] = (char*)b10; 223 b10[4000] = malloc (1000); 224 225 fprintf(stderr, "expecting no leaks\n"); 226 fflush(stderr); 227 VALGRIND_DO_LEAK_CHECK; 228 229 // make b10[4000] undefined. This should create a leak. 230 (void) VALGRIND_MAKE_MEM_UNDEFINED (&b10[4000], sizeof(char*)); 231 fprintf(stderr, "expecting a leak\n"); 232 fflush(stderr); 233 VALGRIND_DO_LEAK_CHECK; 234 235 // make b10[4000] defined again. 236 (void) VALGRIND_MAKE_MEM_DEFINED (&b10[4000], sizeof(char*)); 237 238 // now make some bricolage to have some pages around b10[4000] 239 // unreadable. The leak check should recover from that 240 // thanks to a SEGV handler and a setjmp/longjmp. 241 // This setjmp/longjmp is useful if there is a desync between 242 // the aspacemgr and the real pages mapping. 243 // To have such a discrepancy, we resort on a non SIMD call 244 // to mprotect the pages : as this syscall will not be seen 245 // by Valgrind core, the aspacemgr will not get a chance 246 // to stay synchronised. 247 pagesize = sysconf(_SC_PAGE_SIZE); 248 if (pagesize == -1) 249 perror ("sysconf failed"); 250 251 if (RUNNING_ON_VALGRIND) 252 (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect, RNDPAGEDOWN(&b10[4000]), 2 * pagesize); 253 else 254 mprotect_result = mprotect((void*) RNDPAGEDOWN(&b10[4000]), 2 * pagesize, PROT_NONE); 255 fprintf(stderr, "mprotect result %d\n", mprotect_result); 256 257 fprintf(stderr, "expecting a leak again\n"); 258 fflush(stderr); 259 VALGRIND_DO_LEAK_CHECK; 260 261 if (RUNNING_ON_VALGRIND) 262 (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect, 263 RNDPAGEDOWN(&b10[0]), 264 RNDPAGEDOWN(&(b10[nr_ptr-1])) 265 - RNDPAGEDOWN(&(b10[0]))); 266 else 267 mprotect_result = mprotect((void*) RNDPAGEDOWN(&b10[0]), 268 RNDPAGEDOWN(&(b10[nr_ptr-1])) 269 - RNDPAGEDOWN(&(b10[0])), 270 PROT_NONE); 271 fprintf(stderr, "full mprotect result %d\n", mprotect_result); 272 273 fprintf(stderr, "expecting a leak again after full mprotect\n"); 274 fflush(stderr); 275 VALGRIND_DO_LEAK_CHECK; 276 277 fprintf(stderr, "finished\n"); 278 } 279 280 int main(void) 281 { 282 DECLARE_LEAK_COUNTERS; 283 284 GET_INITIAL_LEAK_COUNTS; 285 286 f(); // see leak-cases.c 287 288 289 GET_FINAL_LEAK_COUNTS; 290 291 PRINT_LEAK_COUNTS(stderr); 292 293 return 0; 294 } 295