Add missing zstd.h to coregrind Makefile.am noinst_HEADERS
[valgrind.git] / memcheck / tests / leak-segv-jmp.c
blob30fe2a1a992f95a2eba035d3c2e920653f5ea4f1
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>
10 typedef unsigned int UInt;
11 typedef unsigned long UWord;
12 typedef unsigned long long int ULong;
14 // Below code is copied from m_syscall.c
15 // Refer to this file for syscall convention.
16 #if defined(VGP_x86_linux)
17 extern UWord do_syscall_WRK (UWord syscall_no,
18 UWord a1, UWord a2, UWord a3,
19 UWord a4, UWord a5, UWord a6
21 asm(
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"
45 #elif defined(VGP_amd64_linux)
46 extern UWord do_syscall_WRK (
47 UWord syscall_no,
48 UWord a1, UWord a2, UWord a3,
49 UWord a4, UWord a5, UWord a6
51 asm(
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"
67 #elif defined(VGP_ppc32_linux)
68 extern ULong do_syscall_WRK (
69 UWord syscall_no,
70 UWord a1, UWord a2, UWord a3,
71 UWord a4, UWord a5, UWord a6
73 asm(
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"
91 #elif defined(VGP_arm_linux)
92 extern UWord do_syscall_WRK (
93 UWord a1, UWord a2, UWord a3,
94 UWord a4, UWord a5, UWord a6,
95 UWord syscall_no
97 asm(
98 ".text\n"
99 ".globl do_syscall_WRK\n"
100 "do_syscall_WRK:\n"
101 " push {r7, ip}\n"
102 " mov r7, r0\n"
103 " mov r0, r1\n"
104 " mov r1, r2\n"
105 " mov r2, r3\n"
106 " svc 0x0\n"
107 " pop {r7, ip}\n"
108 " bx lr\n"
109 ".previous\n"
112 #elif defined(VGP_arm64_linux)
113 extern UWord do_syscall_WRK (
114 UWord a1, UWord a2, UWord a3,
115 UWord a4, UWord a5, UWord a6,
116 UWord syscall_no
118 asm(
119 ".text\n"
120 ".globl do_syscall_WRK\n"
121 "do_syscall_WRK:\n"
122 " mov x8, x6\n"
123 " mov x6, 0\n"
124 " mov x7, 0\n"
125 " svc 0\n"
126 " ret\n"
127 ".previous\n"
130 #elif defined(VGP_s390x_linux)
131 UWord do_syscall_WRK (
132 UWord syscall_no,
133 UWord arg1, UWord arg2, UWord arg3,
134 UWord arg4, UWord arg5, UWord arg6
137 register UWord __arg1 asm("2") = arg1;
138 register UWord __arg2 asm("3") = arg2;
139 register UWord __arg3 asm("4") = arg3;
140 register UWord __arg4 asm("5") = arg4;
141 register UWord __arg5 asm("6") = arg5;
142 register UWord __arg6 asm("7") = arg6;
143 register ULong __svcres asm("2");
145 __asm__ __volatile__ (
146 "lgr %%r1,%1\n\t"
147 "svc 0\n\t"
148 : "=d" (__svcres)
149 : "a" (syscall_no),
150 "0" (__arg1),
151 "d" (__arg2),
152 "d" (__arg3),
153 "d" (__arg4),
154 "d" (__arg5),
155 "d" (__arg6)
156 : "1", "cc", "memory");
158 return (UWord) (__svcres);
161 #elif defined(VGP_mips64_linux)
162 extern UWord do_syscall_WRK (
163 UWord syscall_no,
164 UWord a1, UWord a2, UWord a3,
165 UWord a4, UWord a5, UWord a6
168 UWord out;
169 __asm__ __volatile__ (
170 "move $v0, %1\n\t"
171 "move $a0, %2\n\t"
172 "move $a1, %3\n\t"
173 "move $a2, %4\n\t"
174 "move $a3, %5\n\t"
175 "move $8, %6\n\t" /* We use numbers because some compilers */
176 "move $9, %7\n\t" /* don't recognize $a4 and $a5 */
177 "syscall\n"
178 "move %0, $v0\n\t"
179 : /*out*/ "=r" (out)
180 : "r"(syscall_no), "r"(a1), "r"(a2), "r"(a3),
181 "r"(a4), "r"(a5), "r"(a6)
182 : "v0", "v1", "a0", "a1", "a2", "a3", "$8", "$9");
183 return out;
186 #elif defined(VGP_x86_solaris)
187 extern ULong
188 do_syscall_WRK(UWord a1, UWord a2, UWord a3,
189 UWord a4, UWord a5, UWord a6,
190 UWord a7, UWord a8,
191 UWord syscall_no,
192 UInt *errflag);
193 asm(
194 ".text\n"
195 ".globl do_syscall_WRK\n"
196 "do_syscall_WRK:\n"
197 " movl 40(%esp), %ecx\n" /* assume syscall success */
198 " movl $0, (%ecx)\n"
199 " movl 36(%esp), %eax\n"
200 " int $0x91\n"
201 " jnc 1f\n" /* jump if success */
202 " movl 40(%esp), %ecx\n" /* syscall failed - set *errflag */
203 " movl $1, (%ecx)\n"
204 "1: ret\n"
205 ".previous\n"
208 #elif defined(VGP_amd64_solaris)
209 extern ULong
210 do_syscall_WRK(UWord a1, UWord a2, UWord a3,
211 UWord a4, UWord a5, UWord a6,
212 UWord a7, UWord a8,
213 UWord syscall_no,
214 UInt *errflag);
215 asm(
216 ".text\n"
217 ".globl do_syscall_WRK\n"
218 "do_syscall_WRK:\n"
219 " movq %rcx, %r10\n" /* pass rcx in r10 instead */
220 " movq 32(%rsp), %rcx\n" /* assume syscall success */
221 " movl $0, (%rcx)\n"
222 " movq 24(%rsp), %rax\n"
223 " syscall\n"
224 " jnc 1f\n" /* jump if success */
225 " movq 32(%rsp), %rcx\n" /* syscall failed - set *errflag */
226 " movl $1, (%rcx)\n"
227 "1: ret\n"
228 ".previous\n"
231 #elif defined(VGP_x86_freebsd)
233 #define __NR_mprotect 74
235 /* Incoming args (syscall number + up to 8 args) are on the stack.
236 FreeBSD has a syscall called 'syscall' that takes all args (including
237 the syscall number) off the stack. Since we're called, the return
238 address is on the stack as expected, so we can just call syscall(2)
239 and it Just Works. Error is when carry is set.
241 extern ULong do_syscall_WRK (
242 UWord syscall_no,
243 UWord a1, UWord a2, UWord a3,
244 UWord a4, UWord a5, UWord a6,
245 UWord a7, UWord a8, UInt *flags
247 asm(
248 ".text\n"
249 "do_syscall_WRK:\n"
250 " movl $0,%eax\n" /* syscall number = "syscall" (0) to avoid stack frobbing
252 " int $0x80\n"
253 " jb 1f\n"
254 " ret\n"
255 "1: movl 40(%esp),%ecx\n" /* store carry in *flags */
256 " movl $1,(%ecx)\n"
257 " ret\n"
258 ".previous\n"
261 #elif defined(VGP_amd64_freebsd)
263 #define __NR_mprotect 74
265 extern UWord do_syscall_WRK (
266 UWord syscall_no, /* %rdi */
267 UWord a1, /* %rsi */
268 UWord a2, /* %rdx */
269 UWord a3, /* %rcx */
270 UWord a4, /* %r8 */
271 UWord a5, /* %r9 */
272 UWord a6, /* 8(%rsp) */
273 UWord a7, /* 16(%rsp) */
274 UWord a8, /* 24(%rsp) */
275 UInt *flags, /* 32(%rsp) */
276 UWord *rv2 /* 40(%rsp) */
278 asm(
279 ".text\n"
280 "do_syscall_WRK:\n"
281 /* Convert function calling convention --> syscall calling
282 convention */
283 " pushq %rbp\n"
284 " movq %rsp, %rbp\n"
285 " movq %rdi, %rax\n" /* syscall_no */
286 " movq %rsi, %rdi\n" /* a1 */
287 " movq %rdx, %rsi\n" /* a2 */
288 " movq %rcx, %rdx\n" /* a3 */
289 " movq %r8, %r10\n" /* a4 */
290 " movq %r9, %r8\n" /* a5 */
291 " movq 16(%rbp), %r9\n" /* a6 last arg from stack, account for %rbp */
292 " movq 24(%rbp), %r11\n" /* a7 from stack */
293 " pushq %r11\n"
294 " movq 32(%rbp), %r11\n" /* a8 from stack */
295 " pushq %r11\n"
296 " subq $8,%rsp\n" /* fake return addr */
297 " syscall\n"
298 " jb 1f\n"
299 " movq 48(%rbp),%rsi\n"
300 " movq %rdx, (%rsi)\n"
301 " movq %rbp, %rsp\n"
302 " popq %rbp\n"
303 " ret\n"
304 "1:\n"
305 " movq 40(%rbp), %rsi\n"
306 " movl $1,(%rsi)\n"
307 " movq %rbp, %rsp\n"
308 " popq %rbp\n"
309 " ret\n"
310 ".previous\n"
313 #elif defined(VGP_arm64_freebsd)
315 #define __NR_mprotect 74
317 extern UWord do_syscall_WRK (
318 UWord syscall_no,
319 UWord a1, UWord a2, UWord a3,
320 UWord a4, UWord a5, UWord a6,
321 UWord a7, UWord a8,
322 UInt *flags,
323 UWord *rv2
325 asm(
326 ".text\n"
327 ".globl do_syscall_WRK\n"
328 "do_syscall_WRK:\n"
329 " ldr x8, [sp, #8] \n" /* assume syscall success */
330 " str xzr, [x8] \n"
331 " ldr x8, [sp, #0] \n" /* load syscall_no */
332 " svc 0x0 \n"
333 " bcc 1f \n" /* jump if success */
334 " ldr x9, [sp, #8] \n" /* syscall failed - set *errflag */
335 " mov x10, #1 \n"
336 " str x10, [x9] \n"
337 " 1: ldr x9, [sp, #16] \n" /* save 2nd result word */
338 " str x1, [x9] \n"
339 " ret \n" /* return 1st result word */
340 ".previous\n"
343 #else
344 // Ensure the file compiles even if the syscall nr is not defined.
345 #ifndef __NR_mprotect
346 #define __NR_mprotect 0
347 #endif
348 UWord do_syscall_WRK (UWord syscall_no,
349 UWord a1, UWord a2, UWord a3,
350 UWord a4, UWord a5, UWord a6
353 // not implemented. vgtest prereq should avoid this to be called.
354 return -1;
356 #endif
360 char **b10;
361 char *interior_ptrs[3];
362 int mprotect_result = 0;
363 static void non_simd_mprotect (long tid, void* addr, long len)
365 #if defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
366 UInt err = 0;
367 mprotect_result = do_syscall_WRK((UWord) addr, len, PROT_NONE,
368 0, 0, 0, 0, 0, SYS_mprotect,
369 &err);
370 if (err)
371 mprotect_result = -1;
372 #elif defined(VGP_arm64_linux)
373 mprotect_result = do_syscall_WRK((UWord) addr, len, PROT_NONE,
374 0, 0, 0,
375 __NR_mprotect);
376 #elif defined(VGP_x86_freebsd)
378 UInt flags = 0U;
379 mprotect_result = do_syscall_WRK(__NR_mprotect,
380 (UWord) addr, len, PROT_NONE,
381 0, 0, 0, 0, 0, &flags);
382 #elif defined(VGP_amd64_freebsd) || defined(VGP_arm64_freebsd)
384 UInt flags = 0U;
385 UWord rv2 = 0U;
386 mprotect_result = do_syscall_WRK(__NR_mprotect,
387 (UWord) addr, len, PROT_NONE,
388 0, 0, 0, 0, 0, &flags, &rv2);
390 #else
391 mprotect_result = do_syscall_WRK(__NR_mprotect,
392 (UWord) addr, len, PROT_NONE,
393 0, 0, 0);
394 #endif
397 // can this work without global variable for return value?
398 static void my_mprotect_none(void* addr, long len)
400 if (RUNNING_ON_VALGRIND)
401 (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect,
402 addr,
403 len);
404 else
405 mprotect_result = mprotect(addr,
406 len,
407 PROT_NONE);
410 void f(void)
412 long pagesize;
413 #define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1))
414 int i;
415 const int nr_ptr = (10000 * 20)/sizeof(char*);
417 b10 = calloc (nr_ptr * sizeof(char*), 1);
418 for (i = 0; i < nr_ptr; i++)
419 b10[i] = (char*)b10;
420 b10[4000] = malloc (1000);
422 fprintf(stderr, "expecting no leaks\n");
423 fflush(stderr);
424 VALGRIND_DO_LEAK_CHECK;
426 // make b10[4000] undefined. This should create a leak.
427 (void) VALGRIND_MAKE_MEM_UNDEFINED (&b10[4000], sizeof(char*));
428 fprintf(stderr, "expecting a leak\n");
429 fflush(stderr);
430 VALGRIND_DO_LEAK_CHECK;
432 // make b10[4000] defined again.
433 (void) VALGRIND_MAKE_MEM_DEFINED (&b10[4000], sizeof(char*));
435 // now make some bricolage to have some pages around b10[4000]
436 // unreadable. The leak check should recover from that
437 // thanks to a SEGV handler and a setjmp/longjmp.
438 // This setjmp/longjmp is useful if there is a desync between
439 // the aspacemgr and the real pages mapping.
440 // To have such a discrepancy, we resort on a non SIMD call
441 // to mprotect the pages : as this syscall will not be seen
442 // by Valgrind core, the aspacemgr will not get a chance
443 // to stay synchronised.
444 pagesize = sysconf(_SC_PAGE_SIZE);
445 if (pagesize == -1)
446 perror ("sysconf failed");
448 my_mprotect_none((void*) RNDPAGEDOWN(&b10[4000]), 2 * pagesize);
449 fprintf(stderr, "mprotect result %d\n", mprotect_result);
451 fprintf(stderr, "expecting a leak again\n");
452 fflush(stderr);
453 VALGRIND_DO_LEAK_CHECK;
455 my_mprotect_none((void*) RNDPAGEDOWN(&b10[0]),
456 RNDPAGEDOWN(&(b10[nr_ptr-1]))
457 - RNDPAGEDOWN(&(b10[0])));
458 fprintf(stderr, "full mprotect result %d\n", mprotect_result);
460 fprintf(stderr, "expecting a leak again after full mprotect\n");
461 fflush(stderr);
462 VALGRIND_DO_LEAK_CHECK;
464 // allocate memory but keep only interior pointers to trigger various
465 // heuristics
466 // Allocate some memory:
467 interior_ptrs[0] = calloc (nr_ptr * sizeof(char*), 1);
469 // Inner pointer after 3 sizeT: triggers the stdstring heuristic:
470 interior_ptrs[2] = interior_ptrs[0] + 3 * sizeof(size_t);
472 // Inner pointer after 1 ULong: triggers the length64 heuristic:
473 interior_ptrs[1] = interior_ptrs[0] + sizeof(unsigned long);
475 // Inner pointer after a size: triggers the newarray heuristics.
476 interior_ptrs[0] += sizeof(size_t);
478 my_mprotect_none( (void*) RNDPAGEDOWN((interior_ptrs[0] - sizeof(size_t))),
479 RNDPAGEDOWN(nr_ptr * sizeof(char*)));
480 fprintf(stderr, "mprotect result %d\n", mprotect_result);
482 fprintf(stderr, "expecting heuristic not to crash after full mprotect\n");
483 fflush(stderr);
484 VALGRIND_DO_LEAK_CHECK;
486 fprintf(stderr, "finished\n");
489 int main(void)
491 DECLARE_LEAK_COUNTERS;
493 GET_INITIAL_LEAK_COUNTS;
495 f(); // see leak-cases.c
498 GET_FINAL_LEAK_COUNTS;
500 PRINT_LEAK_COUNTS(stderr);
502 return 0;