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