|
From: <sv...@va...> - 2012-09-14 21:07:07
|
philippe 2012-09-14 22:10:15 +0100 (Fri, 14 Sep 2012)
New Revision: 12972
Log:
Add a test which checks the leak search recovery mechanism
The leak search must recover if unreadable pages are scanned.
This test creates such unreadable pages by doing non SIMD mprotect
syscall (not seen by the aspacemgr).
Added files:
trunk/memcheck/tests/leak-segv-jmp.c
trunk/memcheck/tests/leak-segv-jmp.stderr.exp
trunk/memcheck/tests/leak-segv-jmp.vgtest
Modified files:
trunk/memcheck/tests/Makefile.am
Added: trunk/memcheck/tests/leak-segv-jmp.stderr.exp (+66 -0)
===================================================================
--- trunk/memcheck/tests/leak-segv-jmp.stderr.exp 2012-09-14 17:07:37 +01:00 (rev 12971)
+++ trunk/memcheck/tests/leak-segv-jmp.stderr.exp 2012-09-14 22:10:15 +01:00 (rev 12972)
@@ -0,0 +1,66 @@
+
+All heap blocks were freed -- no leaks are possible
+
+expecting no leaks
+LEAK SUMMARY:
+ definitely lost: 0 bytes in 0 blocks
+ indirectly lost: 0 bytes in 0 blocks
+ possibly lost: 0 bytes in 0 blocks
+ still reachable: 41,000 bytes in 2 blocks
+ suppressed: 0 bytes in 0 blocks
+Reachable blocks (those to which a pointer was found) are not shown.
+To see them, rerun with: --leak-check=full --show-reachable=yes
+
+expecting a leak
+1,000 bytes in 1 blocks are definitely lost in loss record ... of ...
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: f (leak-segv-jmp.c:167)
+ by 0x........: main (leak-segv-jmp.c:214)
+
+LEAK SUMMARY:
+ definitely lost: 1,000 bytes in 1 blocks
+ indirectly lost: 0 bytes in 0 blocks
+ possibly lost: 0 bytes in 0 blocks
+ still reachable: 40,000 bytes in 1 blocks
+ suppressed: 0 bytes in 0 blocks
+Reachable blocks (those to which a pointer was found) are not shown.
+To see them, rerun with: --leak-check=full --show-reachable=yes
+
+mprotect result 0
+expecting a leak again
+1,000 bytes in 1 blocks are definitely lost in loss record ... of ...
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: f (leak-segv-jmp.c:167)
+ by 0x........: main (leak-segv-jmp.c:214)
+
+LEAK SUMMARY:
+ definitely lost: 1,000 bytes in 1 blocks
+ indirectly lost: 0 bytes in 0 blocks
+ possibly lost: 0 bytes in 0 blocks
+ still reachable: 40,000 bytes in 1 blocks
+ suppressed: 0 bytes in 0 blocks
+Reachable blocks (those to which a pointer was found) are not shown.
+To see them, rerun with: --leak-check=full --show-reachable=yes
+
+finished
+LEAK SUMMARY:
+ definitely lost: 1,000 bytes in 1 blocks
+ indirectly lost: 0 bytes in 0 blocks
+ possibly lost: 0 bytes in 0 blocks
+ still reachable: 40,000 bytes in 1 blocks
+ suppressed: 0 bytes in 0 blocks
+Rerun with --leak-check=full to see details of leaked memory
+
+leaked: 1000 bytes in 1 blocks
+dubious: 0 bytes in 0 blocks
+reachable: 40000 bytes in 1 blocks
+suppressed: 0 bytes in 0 blocks
+
+HEAP SUMMARY:
+ in use at exit: 41,000 bytes in 2 blocks
+ total heap usage: 2 allocs, 0 frees, 41,000 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Modified: trunk/memcheck/tests/Makefile.am (+2 -0)
===================================================================
--- trunk/memcheck/tests/Makefile.am 2012-09-14 17:07:37 +01:00 (rev 12971)
+++ trunk/memcheck/tests/Makefile.am 2012-09-14 22:10:15 +01:00 (rev 12972)
@@ -114,6 +114,7 @@
leak-pool-4.vgtest leak-pool-4.stderr.exp \
leak-pool-5.vgtest leak-pool-5.stderr.exp \
leak-tree.vgtest leak-tree.stderr.exp \
+ leak-segv-jmp.vgtest leak-segv-jmp.stderr.exp \
long_namespace_xml.vgtest long_namespace_xml.stdout.exp \
long_namespace_xml.stderr.exp \
long-supps.vgtest long-supps.stderr.exp long-supps.supp \
@@ -259,6 +260,7 @@
leak-delta \
leak-pool \
leak-tree \
+ leak-segv-jmp \
long_namespace_xml \
long-supps \
mallinfo \
Added: trunk/memcheck/tests/leak-segv-jmp.vgtest (+2 -0)
===================================================================
--- trunk/memcheck/tests/leak-segv-jmp.vgtest 2012-09-14 17:07:37 +01:00 (rev 12971)
+++ trunk/memcheck/tests/leak-segv-jmp.vgtest 2012-09-14 22:10:15 +01:00 (rev 12972)
@@ -0,0 +1,2 @@
+prereq: test ! `../../tests/os_test darwin` && ! `../../tests/arch_test mips32` && ! `../../tests/arch_test ppc64`
+prog: leak-segv-jmp
Added: trunk/memcheck/tests/leak-segv-jmp.c (+222 -0)
===================================================================
--- trunk/memcheck/tests/leak-segv-jmp.c 2012-09-14 17:07:37 +01:00 (rev 12971)
+++ trunk/memcheck/tests/leak-segv-jmp.c 2012-09-14 22:10:15 +01:00 (rev 12972)
@@ -0,0 +1,222 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "../memcheck.h"
+#include "leak.h"
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+typedef unsigned long UWord;
+extern UWord do_syscall_WRK (UWord syscall_no,
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6
+ );
+// Below code is copied from m_syscall.c
+// Refer to this file for syscall convention.
+#if defined(VGP_x86_linux)
+asm(
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+" push %esi\n"
+" push %edi\n"
+" push %ebx\n"
+" push %ebp\n"
+" movl 16+ 4(%esp),%eax\n"
+" movl 16+ 8(%esp),%ebx\n"
+" movl 16+12(%esp),%ecx\n"
+" movl 16+16(%esp),%edx\n"
+" movl 16+20(%esp),%esi\n"
+" movl 16+24(%esp),%edi\n"
+" movl 16+28(%esp),%ebp\n"
+" int $0x80\n"
+" popl %ebp\n"
+" popl %ebx\n"
+" popl %edi\n"
+" popl %esi\n"
+" ret\n"
+".previous\n"
+);
+#elif defined(VGP_amd64_linux)
+extern UWord do_syscall_WRK (
+ UWord syscall_no,
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6
+ );
+asm(
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+" movq %rdi, %rax\n"
+" movq %rsi, %rdi\n"
+" movq %rdx, %rsi\n"
+" movq %rcx, %rdx\n"
+" movq %r8, %r10\n"
+" movq %r9, %r8\n"
+" movq 8(%rsp), %r9\n" /* last arg from stack */
+" syscall\n"
+" ret\n"
+".previous\n"
+);
+
+#elif defined(VGP_ppc32_linux)
+extern ULong do_syscall_WRK (
+ UWord syscall_no,
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6
+ );
+asm(
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+" mr 0,3\n"
+" mr 3,4\n"
+" mr 4,5\n"
+" mr 5,6\n"
+" mr 6,7\n"
+" mr 7,8\n"
+" mr 8,9\n"
+" sc\n" /* syscall: sets %cr0.so on error */
+" mfcr 4\n" /* %cr -> low word of return var */
+" rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
+" blr\n" /* and return */
+".previous\n"
+);
+
+#elif defined(VGP_arm_linux)
+extern UWord do_syscall_WRK (
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6,
+ UWord syscall_no
+ );
+asm(
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+" push {r4, r5, r7}\n"
+" ldr r4, [sp, #12]\n"
+" ldr r5, [sp, #16]\n"
+" ldr r7, [sp, #20]\n"
+" svc 0x0\n"
+" pop {r4, r5, r7}\n"
+" bx lr\n"
+".previous\n"
+);
+#elif defined(VGP_s390x_linux)
+typedef unsigned long long int ULong;
+UWord do_syscall_WRK (
+ UWord syscall_no,
+ UWord arg1, UWord arg2, UWord arg3,
+ UWord arg4, UWord arg5, UWord arg6
+ )
+{
+ register UWord __arg1 asm("2") = arg1;
+ register UWord __arg2 asm("3") = arg2;
+ register UWord __arg3 asm("4") = arg3;
+ register UWord __arg4 asm("5") = arg4;
+ register UWord __arg5 asm("6") = arg5;
+ register UWord __arg6 asm("7") = arg6;
+ register ULong __svcres asm("2");
+
+ __asm__ __volatile__ (
+ "lgr %%r1,%1\n\t"
+ "svc 0\n\t"
+ : "=d" (__svcres)
+ : "a" (syscall_no),
+ "0" (__arg1),
+ "d" (__arg2),
+ "d" (__arg3),
+ "d" (__arg4),
+ "d" (__arg5),
+ "d" (__arg6)
+ : "1", "cc", "memory");
+
+ return (UWord) (__svcres);
+}
+
+#else
+UWord do_syscall_WRK (UWord syscall_no,
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6
+ )
+{
+ // not implemented. vgtest prereq should avoid this to be called.
+ return -1;
+}
+#endif
+
+
+
+char **b10;
+int mprotect_result = 0;
+static void non_simd_mprotect (long tid, void* addr, long len)
+{
+ mprotect_result = do_syscall_WRK(__NR_mprotect,
+ (UWord) addr, len, PROT_NONE,
+ 0, 0, 0);
+}
+
+void f(void)
+{
+ long pagesize;
+#define RNDPAGEDOWN(a) ((long)a & ~(pagesize-1))
+
+ b10 = malloc ((10000 * 4)/sizeof(char*) * sizeof(char*));
+
+ b10[4000] = malloc (1000);
+
+ fprintf(stderr, "expecting no leaks\n");
+ fflush(stderr);
+ VALGRIND_DO_LEAK_CHECK;
+
+ // make b10[4000] undefined. This should create a leak.
+ VALGRIND_MAKE_MEM_UNDEFINED (&b10[4000], sizeof(char*));
+ fprintf(stderr, "expecting a leak\n");
+ fflush(stderr);
+ VALGRIND_DO_LEAK_CHECK;
+
+ // make b10[4000] defined again.
+ VALGRIND_MAKE_MEM_DEFINED (&b10[4000], sizeof(char*));
+
+ // now make some bricolage to have some pages around b10[4000]
+ // unreadable. The leak check should recover from that
+ // thanks to a SEGV handler and a setjmp/longjmp.
+ // This setjmp/longjmp is useful if there is a desync between
+ // the aspacemgr and the real pages mapping.
+ // To have such a discrepancy, we resort on a non SIMD call
+ // to mprotect the pages : as this syscall will not be seen
+ // by Valgrind core, the aspacemgr will not get a chance
+ // to stay synchronised.
+ pagesize = sysconf(_SC_PAGE_SIZE);
+ if (pagesize == -1)
+ perror ("sysconf failed");
+
+ if (RUNNING_ON_VALGRIND)
+ VALGRIND_NON_SIMD_CALL2(non_simd_mprotect, RNDPAGEDOWN(&b10[4000]), 2 * pagesize);
+ else
+ mprotect_result = mprotect((void*) RNDPAGEDOWN(&b10[4000]), 2 * pagesize, PROT_NONE);
+ fprintf(stderr, "mprotect result %d\n", mprotect_result);
+
+ fprintf(stderr, "expecting a leak again\n");
+ fflush(stderr);
+ VALGRIND_DO_LEAK_CHECK;
+
+ fprintf(stderr, "finished\n");
+}
+
+int main(void)
+{
+ DECLARE_LEAK_COUNTERS;
+
+ GET_INITIAL_LEAK_COUNTS;
+
+ f(); // see leak-cases.c
+
+
+ GET_FINAL_LEAK_COUNTS;
+
+ PRINT_LEAK_COUNTS(stderr);
+
+ return 0;
+}
|