|
From: Jeremy F. <je...@go...> - 2005-02-22 02:40:04
|
CVS commit by fitzhardinge:
It is an absolute no-no to change the signal handlers, so fix the
leak-checking code to avoid it. The core fault signal handler now allows
tools to register a catcher for when they want to see SIGSEGV/BUS,
as the leak-checker does. Also, add a test case to make sure
pointer-tracing avoids all the possible traps.
A memcheck/tests/pointer-trace.c 1.1 [no copyright]
A memcheck/tests/pointer-trace.stderr.exp 1.1
A memcheck/tests/pointer-trace.vgtest 1.1
M +2 -2 addrcheck/ac_main.c 1.78
M +19 -0 coregrind/vg_signals.c 1.127
M +5 -0 include/tool.h.base 1.23
M +18 -54 memcheck/mac_leakcheck.c 1.17
M +2 -2 memcheck/mc_main.c 1.64
M +3 -0 memcheck/tests/Makefile.am 1.67
--- valgrind/include/tool.h.base #1.22:1.23
@@ -505,4 +505,9 @@
extern Bool VG_(is_valgrind_addr)(Addr a);
+/* Register an interest in apparently internal faults; used code which
+ wanders around dangerous memory (ie, leakcheck). The catcher is
+ not expected to return. */
+extern void VG_(set_fault_catcher)(void (*catcher)(Int sig, Addr addr));
+
/* initialize shadow pages in the range [p, p+sz) This calls
init_shadow_page for each one. It should be a lot more efficient
--- valgrind/addrcheck/ac_main.c #1.77:1.78
@@ -1124,6 +1124,6 @@ static
Bool ac_is_valid_64k_chunk ( UInt chunk_number )
{
- sk_assert(chunk_number >= 0 && chunk_number < 65536);
- if (IS_DISTINGUISHED_SM(primary_map[chunk_number])) {
+ sk_assert(chunk_number >= 0 && chunk_number < PRIMARY_SIZE);
+ if (primary_map[chunk_number] == DSM_NOTADDR) {
/* Definitely not in use. */
return False;
--- valgrind/memcheck/mac_leakcheck.c #1.16:1.17
@@ -47,6 +47,9 @@ jmp_buf memscan_jmpbuf;
static
-void vg_scan_all_valid_memory_sighandler ( Int sigNo )
+void vg_scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
{
+ if (0)
+ VG_(printf)("OUCH! sig=%d addr=%p\n", sigNo, addr);
+ if (sigNo == VKI_SIGSEGV || sigNo == VKI_SIGBUS)
__builtin_longjmp(memscan_jmpbuf, 1);
}
@@ -77,46 +79,11 @@ UInt vg_scan_all_valid_memory ( Bool is_
volatile Bool anyValid;
volatile Addr pageBase, addr;
- volatile UInt res, numPages, page, primaryMapNo;
+ volatile UInt numPages, page, primaryMapNo;
volatile UInt page_first_word, nWordsNotified;
+ vki_sigset_t sigmask;
- struct vki_sigaction sigbus_saved;
- struct vki_sigaction sigbus_new;
- struct vki_sigaction sigsegv_saved;
- struct vki_sigaction sigsegv_new;
- vki_sigset_t blockmask_saved;
- vki_sigset_t unblockmask_new;
-
- /* Temporarily install a new sigsegv and sigbus handler, and make
- sure SIGBUS, SIGSEGV and SIGTERM are unblocked. (Perhaps the
- first two can never be blocked anyway?) */
-
- sigbus_new.ksa_handler = vg_scan_all_valid_memory_sighandler;
- sigbus_new.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
- sigbus_new.sa_restorer = NULL;
- res = VG_(sigemptyset)( &sigbus_new.sa_mask );
- sk_assert(res == 0);
-
- sigsegv_new.ksa_handler = vg_scan_all_valid_memory_sighandler;
- sigsegv_new.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
- sigsegv_new.sa_restorer = NULL;
- res = VG_(sigemptyset)( &sigsegv_new.sa_mask );
- sk_assert(res == 0+0);
-
- res = VG_(sigemptyset)( &unblockmask_new );
- res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGBUS );
- res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGSEGV );
- res |= VG_(sigaddset)( &unblockmask_new, VKI_SIGTERM );
- sk_assert(res == 0+0+0);
-
- res = VG_(sigaction)( VKI_SIGBUS, &sigbus_new, &sigbus_saved );
- sk_assert(res == 0+0+0+0);
-
- res = VG_(sigaction)( VKI_SIGSEGV, &sigsegv_new, &sigsegv_saved );
- sk_assert(res == 0+0+0+0+0);
-
- res = VG_(sigprocmask)( VKI_SIG_UNBLOCK, &unblockmask_new, &blockmask_saved );
- sk_assert(res == 0+0+0+0+0+0);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
+ VG_(set_fault_catcher)(vg_scan_all_valid_memory_catcher);
- /* The signal handlers are installed. Actually do the memory scan. */
numPages = 1 << (32-VKI_PAGE_SHIFT);
sk_assert(numPages == 1048576);
@@ -155,10 +122,10 @@ UInt vg_scan_all_valid_memory ( Bool is_
/* Ok, we have to prod cautiously at the page and see if it
explodes or not. */
- if (__builtin_setjmp(memscan_jmpbuf) == 0) {
- /* try this ... */
+ if (VG_(is_addressable)(pageBase, sizeof(UInt), VKI_PROT_READ) &&
+ __builtin_setjmp(memscan_jmpbuf) == 0) {
page_first_word = * (volatile UInt*)pageBase;
/* we get here if we didn't get a fault */
/* Scan the page */
- for (addr = pageBase; addr < pageBase+VKI_PAGE_SIZE; addr += 4) {
+ for (addr = pageBase; addr < pageBase+VKI_PAGE_SIZE; addr += sizeof(void *)) {
if (is_valid_address(addr)) {
nWordsNotified++;
@@ -170,4 +137,8 @@ UInt vg_scan_all_valid_memory ( Bool is_
fault, which in turn caused the signal handler to longjmp.
Ignore this page. */
+
+ /* We need to restore the signal mask, because we were
+ longjmped out of a signal handler. */
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
if (0)
VG_(printf)(
@@ -178,13 +149,6 @@ UInt vg_scan_all_valid_memory ( Bool is_
}
- /* Restore signal state to whatever it was before. */
- res = VG_(sigaction)( VKI_SIGBUS, &sigbus_saved, NULL );
- sk_assert(res == 0 +0);
-
- res = VG_(sigaction)( VKI_SIGSEGV, &sigsegv_saved, NULL );
- sk_assert(res == 0 +0 +0);
-
- res = VG_(sigprocmask)( VKI_SIG_SETMASK, &blockmask_saved, NULL );
- sk_assert(res == 0 +0 +0 +0);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &sigmask, NULL);
+ VG_(set_fault_catcher)(NULL);
return nWordsNotified;
--- valgrind/memcheck/mc_main.c #1.63:1.64
@@ -1523,6 +1523,6 @@ static
Bool mc_is_valid_64k_chunk ( UInt chunk_number )
{
- sk_assert(chunk_number >= 0 && chunk_number < 65536);
- if (IS_DISTINGUISHED_SM(primary_map[chunk_number])) {
+ sk_assert(chunk_number >= 0 && chunk_number < PRIMARY_SIZE);
+ if (primary_map[chunk_number] == DSM_NOTADDR) {
/* Definitely not in use. */
return False;
--- valgrind/coregrind/vg_signals.c #1.126:1.127
@@ -1687,4 +1687,15 @@ Bool VG_(extend_stack)(Addr addr, UInt m
}
+static void (*fault_catcher)(Int sig, Addr addr);
+
+void VG_(set_fault_catcher)(void (*catcher)(Int, Addr))
+{
+ if (catcher != NULL && fault_catcher != NULL)
+ VG_(core_panic)("Fault catcher is already registered");
+
+ fault_catcher = catcher;
+}
+
+
/*
Recieve a sync signal from the host.
@@ -1835,4 +1846,12 @@ void vg_sync_signalhandler ( Int sigNo,
}
+ /* Check to see if someone is interested in faults. */
+ if (fault_catcher) {
+ (*fault_catcher)(sigNo, (Addr)info->_sifields._sigfault._addr);
+
+ /* If the catcher returns, then it didn't handle the fault,
+ so carry on panicing. */
+ }
+
/* If resume_scheduler returns or its our fault, it means we
don't have longjmp set up, implying that we weren't running
--- valgrind/memcheck/tests/Makefile.am #1.66:1.67
@@ -51,4 +51,5 @@
null_socket.stderr.exp null_socket.vgtest \
overlap.stderr.exp overlap.stdout.exp overlap.vgtest \
+ pointer-trace.vgtest pointer-trace.stdout.exp pointer-trace.stderr.exp \
post-syscall.stderr.exp post-syscall.stdout.exp post-syscall.vgtest \
pth_once.stderr.exp pth_once.stdout.exp pth_once.vgtest \
@@ -90,4 +91,5 @@
nanoleak new_nothrow \
null_socket overlap \
+ pointer-trace \
post-syscall \
realloc1 realloc2 realloc3 \
@@ -143,4 +145,5 @@
null_socket_SOURCES = null_socket.c
overlap_SOURCES = overlap.c
+pointer_trace_SOURCES = pointer-trace.c
post_syscall_SOURCES = post-syscall.c
realloc1_SOURCES = realloc1.c
|