• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
do_syscall_WRK(UWord syscall_no,UWord arg1,UWord arg2,UWord arg3,UWord arg4,UWord arg5,UWord arg6)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)
do_syscall_WRK(UWord syscall_no,UWord a1,UWord a2,UWord a3,UWord a4,UWord a5,UWord a6)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)
do_syscall_WRK(UWord syscall_no,UWord a1,UWord a2,UWord a3,UWord a4,UWord a5,UWord a6)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
do_syscall_WRK(UWord syscall_no,UWord a1,UWord a2,UWord a3,UWord a4,UWord a5,UWord a6)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;
non_simd_mprotect(long tid,void * addr,long len)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 
f(void)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 
main(void)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