Home | History | Annotate | Download | only in tests
      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 
    163 #else
    164 // Ensure the file compiles even if the syscall nr is not defined.
    165 #ifndef __NR_mprotect
    166 #define __NR_mprotect 0
    167 #endif
    168 UWord do_syscall_WRK (UWord syscall_no,
    169                       UWord a1, UWord a2, UWord a3,
    170                       UWord a4, UWord a5, UWord a6
    171                       )
    172 {
    173    // not implemented. vgtest prereq should avoid this to be called.
    174    return -1;
    175 }
    176 #endif
    177 
    178 
    179 
    180 char **b10;
    181 int mprotect_result = 0;
    182 static void non_simd_mprotect (long tid, void* addr, long len)
    183 {
    184    mprotect_result = do_syscall_WRK(__NR_mprotect,
    185                                     (UWord) addr, len, PROT_NONE,
    186                                     0, 0, 0);
    187 }
    188 
    189 void f(void)
    190 {
    191    long pagesize;
    192 #define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1))
    193    int i;
    194    const int nr_ptr = (10000 * 4)/sizeof(char*);
    195 
    196    b10 = calloc (nr_ptr * sizeof(char*), 1);
    197    for (i = 0; i < nr_ptr; i++)
    198       b10[i] = (char*)b10;
    199    b10[4000] = malloc (1000);
    200 
    201    fprintf(stderr, "expecting no leaks\n");
    202    fflush(stderr);
    203    VALGRIND_DO_LEAK_CHECK;
    204 
    205    // make b10[4000] undefined. This should create a leak.
    206    (void) VALGRIND_MAKE_MEM_UNDEFINED (&b10[4000], sizeof(char*));
    207    fprintf(stderr, "expecting a leak\n");
    208    fflush(stderr);
    209    VALGRIND_DO_LEAK_CHECK;
    210 
    211    // make  b10[4000] defined again.
    212    (void) VALGRIND_MAKE_MEM_DEFINED (&b10[4000], sizeof(char*));
    213 
    214    // now make some bricolage to have some pages around b10[4000]
    215    // unreadable. The leak check should recover from that
    216    // thanks to a SEGV handler and a setjmp/longjmp.
    217    // This setjmp/longjmp is useful if there is a desync between
    218    // the aspacemgr and the real pages mapping.
    219    // To have such a discrepancy, we resort on a non SIMD call
    220    // to mprotect the pages : as this syscall will not be seen
    221    // by Valgrind core, the aspacemgr will not get a chance
    222    // to stay synchronised.
    223    pagesize = sysconf(_SC_PAGE_SIZE);
    224    if (pagesize == -1)
    225       perror ("sysconf failed");
    226 
    227    if (RUNNING_ON_VALGRIND)
    228      (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect, RNDPAGEDOWN(&b10[4000]), 2 * pagesize);
    229    else
    230       mprotect_result = mprotect((void*) RNDPAGEDOWN(&b10[4000]), 2 * pagesize, PROT_NONE);
    231    fprintf(stderr, "mprotect result %d\n", mprotect_result);
    232 
    233    fprintf(stderr, "expecting a leak again\n");
    234    fflush(stderr);
    235    VALGRIND_DO_LEAK_CHECK;
    236 
    237    if (RUNNING_ON_VALGRIND)
    238      (void) VALGRIND_NON_SIMD_CALL2(non_simd_mprotect,
    239                                     RNDPAGEDOWN(&b10[0]),
    240                                     RNDPAGEDOWN(&(b10[nr_ptr-1]))
    241                                     - RNDPAGEDOWN(&(b10[0])));
    242    else
    243       mprotect_result = mprotect((void*) RNDPAGEDOWN(&b10[0]),
    244                                  RNDPAGEDOWN(&(b10[nr_ptr-1]))
    245                                  - RNDPAGEDOWN(&(b10[0])),
    246                                  PROT_NONE);
    247    fprintf(stderr, "full mprotect result %d\n", mprotect_result);
    248 
    249    fprintf(stderr, "expecting a leak again after full mprotect\n");
    250    fflush(stderr);
    251    VALGRIND_DO_LEAK_CHECK;
    252 
    253    fprintf(stderr, "finished\n");
    254 }
    255 
    256 int main(void)
    257 {
    258    DECLARE_LEAK_COUNTERS;
    259 
    260    GET_INITIAL_LEAK_COUNTS;
    261 
    262    f();   // see leak-cases.c
    263 
    264 
    265    GET_FINAL_LEAK_COUNTS;
    266 
    267    PRINT_LEAK_COUNTS(stderr);
    268 
    269    return 0;
    270 }
    271