(really) Bug 477630 - Include ucontext.h rather than sys/ucontext.h in Solaris sources
[valgrind.git] / memcheck / tests / leak-segv-jmp.c
blob97bddaf238aef18e14444bd7cf309007e2433813
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 {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"
111 #elif defined(VGP_arm64_linux)
112 extern UWord do_syscall_WRK (
113 UWord a1, UWord a2, UWord a3,
114 UWord a4, UWord a5, UWord a6,
115 UWord syscall_no
117 asm(
118 ".text\n"
119 ".globl do_syscall_WRK\n"
120 "do_syscall_WRK:\n"
121 " mov x8, x6\n"
122 " mov x6, 0\n"
123 " mov x7, 0\n"
124 " svc 0\n"
125 " ret\n"
126 ".previous\n"
129 #elif defined(VGP_s390x_linux)
130 UWord do_syscall_WRK (
131 UWord syscall_no,
132 UWord arg1, UWord arg2, UWord arg3,
133 UWord arg4, UWord arg5, UWord arg6
136 register UWord __arg1 asm("2") = arg1;
137 register UWord __arg2 asm("3") = arg2;
138 register UWord __arg3 asm("4") = arg3;
139 register UWord __arg4 asm("5") = arg4;
140 register UWord __arg5 asm("6") = arg5;
141 register UWord __arg6 asm("7") = arg6;
142 register ULong __svcres asm("2");
144 __asm__ __volatile__ (
145 "lgr %%r1,%1\n\t"
146 "svc 0\n\t"
147 : "=d" (__svcres)
148 : "a" (syscall_no),
149 "0" (__arg1),
150 "d" (__arg2),
151 "d" (__arg3),
152 "d" (__arg4),
153 "d" (__arg5),
154 "d" (__arg6)
155 : "1", "cc", "memory");
157 return (UWord) (__svcres);
160 #elif defined(VGP_mips64_linux)
161 extern UWord do_syscall_WRK (
162 UWord syscall_no,
163 UWord a1, UWord a2, UWord a3,
164 UWord a4, UWord a5, UWord a6
167 UWord out;
168 __asm__ __volatile__ (
169 "move $v0, %1\n\t"
170 "move $a0, %2\n\t"
171 "move $a1, %3\n\t"
172 "move $a2, %4\n\t"
173 "move $a3, %5\n\t"
174 "move $8, %6\n\t" /* We use numbers because some compilers */
175 "move $9, %7\n\t" /* don't recognize $a4 and $a5 */
176 "syscall\n"
177 "move %0, $v0\n\t"
178 : /*out*/ "=r" (out)
179 : "r"(syscall_no), "r"(a1), "r"(a2), "r"(a3),
180 "r"(a4), "r"(a5), "r"(a6)
181 : "v0", "v1", "a0", "a1", "a2", "a3", "$8", "$9");
182 return out;
185 #elif defined(VGP_x86_solaris)
186 extern ULong
187 do_syscall_WRK(UWord a1, UWord a2, UWord a3,
188 UWord a4, UWord a5, UWord a6,
189 UWord a7, UWord a8,
190 UWord syscall_no,
191 UInt *errflag);
192 asm(
193 ".text\n"
194 ".globl do_syscall_WRK\n"
195 "do_syscall_WRK:\n"
196 " movl 40(%esp), %ecx\n" /* assume syscall success */
197 " movl $0, (%ecx)\n"
198 " movl 36(%esp), %eax\n"
199 " int $0x91\n"
200 " jnc 1f\n" /* jump if success */
201 " movl 40(%esp), %ecx\n" /* syscall failed - set *errflag */
202 " movl $1, (%ecx)\n"
203 "1: ret\n"
204 ".previous\n"
207 #elif defined(VGP_amd64_solaris)
208 extern ULong
209 do_syscall_WRK(UWord a1, UWord a2, UWord a3,
210 UWord a4, UWord a5, UWord a6,
211 UWord a7, UWord a8,
212 UWord syscall_no,
213 UInt *errflag);
214 asm(
215 ".text\n"
216 ".globl do_syscall_WRK\n"
217 "do_syscall_WRK:\n"
218 " movq %rcx, %r10\n" /* pass rcx in r10 instead */
219 " movq 32(%rsp), %rcx\n" /* assume syscall success */
220 " movl $0, (%rcx)\n"
221 " movq 24(%rsp), %rax\n"
222 " syscall\n"
223 " jnc 1f\n" /* jump if success */
224 " movq 32(%rsp), %rcx\n" /* syscall failed - set *errflag */
225 " movl $1, (%rcx)\n"
226 "1: ret\n"
227 ".previous\n"
230 #elif defined(VGP_x86_freebsd)
232 #define __NR_mprotect 74
234 /* Incoming args (syscall number + up to 8 args) are on the stack.
235 FreeBSD has a syscall called 'syscall' that takes all args (including
236 the syscall number) off the stack. Since we're called, the return
237 address is on the stack as expected, so we can just call syscall(2)
238 and it Just Works. Error is when carry is set.
240 extern ULong do_syscall_WRK (
241 UWord syscall_no,
242 UWord a1, UWord a2, UWord a3,
243 UWord a4, UWord a5, UWord a6,
244 UWord a7, UWord a8, UInt *flags
246 asm(
247 ".text\n"
248 "do_syscall_WRK:\n"
249 " movl $0,%eax\n" /* syscall number = "syscall" (0) to avoid stack frobbing
251 " int $0x80\n"
252 " jb 1f\n"
253 " ret\n"
254 "1: movl 40(%esp),%ecx\n" /* store carry in *flags */
255 " movl $1,(%ecx)\n"
256 " ret\n"
257 ".previous\n"
260 #elif defined(VGP_amd64_freebsd)
262 #define __NR_mprotect 74
264 extern UWord do_syscall_WRK (
265 UWord syscall_no, /* %rdi */
266 UWord a1, /* %rsi */
267 UWord a2, /* %rdx */
268 UWord a3, /* %rcx */
269 UWord a4, /* %r8 */
270 UWord a5, /* %r9 */
271 UWord a6, /* 8(%rsp) */
272 UWord a7, /* 16(%rsp) */
273 UWord a8, /* 24(%rsp) */
274 UInt *flags, /* 32(%rsp) */
275 UWord *rv2 /* 40(%rsp) */
277 asm(
278 ".text\n"
279 "do_syscall_WRK:\n"
280 /* Convert function calling convention --> syscall calling
281 convention */
282 " pushq %rbp\n"
283 " movq %rsp, %rbp\n"
284 " movq %rdi, %rax\n" /* syscall_no */
285 " movq %rsi, %rdi\n" /* a1 */
286 " movq %rdx, %rsi\n" /* a2 */
287 " movq %rcx, %rdx\n" /* a3 */
288 " movq %r8, %r10\n" /* a4 */
289 " movq %r9, %r8\n" /* a5 */
290 " movq 16(%rbp), %r9\n" /* a6 last arg from stack, account for %rbp */
291 " movq 24(%rbp), %r11\n" /* a7 from stack */
292 " pushq %r11\n"
293 " movq 32(%rbp), %r11\n" /* a8 from stack */
294 " pushq %r11\n"
295 " subq $8,%rsp\n" /* fake return addr */
296 " syscall\n"
297 " jb 1f\n"
298 " movq 48(%rbp),%rsi\n"
299 " movq %rdx, (%rsi)\n"
300 " movq %rbp, %rsp\n"
301 " popq %rbp\n"
302 " ret\n"
303 "1:\n"
304 " movq 40(%rbp), %rsi\n"
305 " movl $1,(%rsi)\n"
306 " movq %rbp, %rsp\n"
307 " popq %rbp\n"
308 " ret\n"
309 ".previous\n"
312 #else
313 // Ensure the file compiles even if the syscall nr is not defined.
314 #ifndef __NR_mprotect
315 #define __NR_mprotect 0
316 #endif
317 UWord do_syscall_WRK (UWord syscall_no,
318 UWord a1, UWord a2, UWord a3,
319 UWord a4, UWord a5, UWord a6
322 // not implemented. vgtest prereq should avoid this to be called.
323 return -1;
325 #endif
329 char **b10;
330 char *interior_ptrs[3];
331 int mprotect_result = 0;
332 static void non_simd_mprotect (long tid, void* addr, long len)
334 #if defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
335 UInt err = 0;
336 mprotect_result = do_syscall_WRK((UWord) addr, len, PROT_NONE,
337 0, 0, 0, 0, 0, SYS_mprotect,
338 &err);
339 if (err)
340 mprotect_result = -1;
341 #elif defined(VGP_arm64_linux)
342 mprotect_result = do_syscall_WRK((UWord) addr, len, PROT_NONE,
343 0, 0, 0,
344 __NR_mprotect);
345 #elif defined(VGP_x86_freebsd)
347 UInt flags = 0U;
348 mprotect_result = do_syscall_WRK(__NR_mprotect,
349 (UWord) addr, len, PROT_NONE,
350 0, 0, 0, 0, 0, &flags);
351 #elif defined(VGP_amd64_freebsd)
353 UInt flags = 0U;
354 UWord rv2 = 0U;
355 mprotect_result = do_syscall_WRK(__NR_mprotect,
356 (UWord) addr, len, PROT_NONE,
357 0, 0, 0, 0, 0, &flags, &rv2);
359 #else
360 mprotect_result = do_syscall_WRK(__NR_mprotect,
361 (UWord) addr, len, PROT_NONE,
362 0, 0, 0);
363 #endif
366 // can this work without global variable for return value?
367 static void my_mprotect_none(void* addr, long len)
369 if (RUNNING_ON_VALGRIND)
370 (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect,
371 addr,
372 len);
373 else
374 mprotect_result = mprotect(addr,
375 len,
376 PROT_NONE);
379 void f(void)
381 long pagesize;
382 #define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1))
383 int i;
384 const int nr_ptr = (10000 * 20)/sizeof(char*);
386 b10 = calloc (nr_ptr * sizeof(char*), 1);
387 for (i = 0; i < nr_ptr; i++)
388 b10[i] = (char*)b10;
389 b10[4000] = malloc (1000);
391 fprintf(stderr, "expecting no leaks\n");
392 fflush(stderr);
393 VALGRIND_DO_LEAK_CHECK;
395 // make b10[4000] undefined. This should create a leak.
396 (void) VALGRIND_MAKE_MEM_UNDEFINED (&b10[4000], sizeof(char*));
397 fprintf(stderr, "expecting a leak\n");
398 fflush(stderr);
399 VALGRIND_DO_LEAK_CHECK;
401 // make b10[4000] defined again.
402 (void) VALGRIND_MAKE_MEM_DEFINED (&b10[4000], sizeof(char*));
404 // now make some bricolage to have some pages around b10[4000]
405 // unreadable. The leak check should recover from that
406 // thanks to a SEGV handler and a setjmp/longjmp.
407 // This setjmp/longjmp is useful if there is a desync between
408 // the aspacemgr and the real pages mapping.
409 // To have such a discrepancy, we resort on a non SIMD call
410 // to mprotect the pages : as this syscall will not be seen
411 // by Valgrind core, the aspacemgr will not get a chance
412 // to stay synchronised.
413 pagesize = sysconf(_SC_PAGE_SIZE);
414 if (pagesize == -1)
415 perror ("sysconf failed");
417 my_mprotect_none((void*) RNDPAGEDOWN(&b10[4000]), 2 * pagesize);
418 fprintf(stderr, "mprotect result %d\n", mprotect_result);
420 fprintf(stderr, "expecting a leak again\n");
421 fflush(stderr);
422 VALGRIND_DO_LEAK_CHECK;
424 my_mprotect_none((void*) RNDPAGEDOWN(&b10[0]),
425 RNDPAGEDOWN(&(b10[nr_ptr-1]))
426 - RNDPAGEDOWN(&(b10[0])));
427 fprintf(stderr, "full mprotect result %d\n", mprotect_result);
429 fprintf(stderr, "expecting a leak again after full mprotect\n");
430 fflush(stderr);
431 VALGRIND_DO_LEAK_CHECK;
433 // allocate memory but keep only interior pointers to trigger various
434 // heuristics
435 // Allocate some memory:
436 interior_ptrs[0] = calloc (nr_ptr * sizeof(char*), 1);
438 // Inner pointer after 3 sizeT: triggers the stdstring heuristic:
439 interior_ptrs[2] = interior_ptrs[0] + 3 * sizeof(size_t);
441 // Inner pointer after 1 ULong: triggers the length64 heuristic:
442 interior_ptrs[1] = interior_ptrs[0] + sizeof(unsigned long);
444 // Inner pointer after a size: triggers the newarray heuristics.
445 interior_ptrs[0] += sizeof(size_t);
447 my_mprotect_none( (void*) RNDPAGEDOWN((interior_ptrs[0] - sizeof(size_t))),
448 RNDPAGEDOWN(nr_ptr * sizeof(char*)));
449 fprintf(stderr, "mprotect result %d\n", mprotect_result);
451 fprintf(stderr, "expecting heuristic not to crash after full mprotect\n");
452 fflush(stderr);
453 VALGRIND_DO_LEAK_CHECK;
455 fprintf(stderr, "finished\n");
458 int main(void)
460 DECLARE_LEAK_COUNTERS;
462 GET_INITIAL_LEAK_COUNTS;
464 f(); // see leak-cases.c
467 GET_FINAL_LEAK_COUNTS;
469 PRINT_LEAK_COUNTS(stderr);
471 return 0;