|
From: <sv...@va...> - 2007-10-30 19:08:05
|
Author: sewardj
Date: 2007-10-30 19:08:01 +0000 (Tue, 30 Oct 2007)
New Revision: 7056
Log:
Add a test program for verifying that wrappers are really working.
Added:
branches/THRCHECK/thrcheck/tests/tc20_verifywrap.c
branches/THRCHECK/thrcheck/tests/tc20_verifywrap.stderr.exp-glibc25-amd64
branches/THRCHECK/thrcheck/tests/tc20_verifywrap.stdout.exp
branches/THRCHECK/thrcheck/tests/tc20_verifywrap.vgtest
Modified:
branches/THRCHECK/thrcheck/tests/Makefile.am
Modified: branches/THRCHECK/thrcheck/tests/Makefile.am
===================================================================
--- branches/THRCHECK/thrcheck/tests/Makefile.am 2007-10-30 01:19:34 UTC (rev 7055)
+++ branches/THRCHECK/thrcheck/tests/Makefile.am 2007-10-30 19:08:01 UTC (rev 7056)
@@ -67,7 +67,9 @@
tc18_semabuse.stderr.exp-glibc25-x86 \
tc19_shadowmem.vgtest tc19_shadowmem.stdout.exp \
tc19_shadowmem.stderr.exp-glibc25-amd64 \
- tc19_shadowmem.stderr.exp-glibc25-x86
+ tc19_shadowmem.stderr.exp-glibc25-x86 \
+ tc20_verifywrap.vgtest tc20_verifywrap.stdout.exp \
+ tc20_verifywrap.stderr.exp-glibc25-amd64
check_PROGRAMS = \
@@ -95,7 +97,8 @@
tc16_byterace \
tc17_sembar \
tc18_semabuse \
- tc19_shadowmem
+ tc19_shadowmem \
+ tc20_verifywrap
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include \
-I$(top_srcdir)/coregrind -I$(top_builddir)/include \
Added: branches/THRCHECK/thrcheck/tests/tc20_verifywrap.c
===================================================================
--- branches/THRCHECK/thrcheck/tests/tc20_verifywrap.c (rev 0)
+++ branches/THRCHECK/thrcheck/tests/tc20_verifywrap.c 2007-10-30 19:08:01 UTC (rev 7056)
@@ -0,0 +1,235 @@
+
+/* This program attempts to verify that all functions that are
+ supposed to be wrapped by tc_intercepts.c really are wrapped. The
+ main way it does this is to cause failures in those functions, so
+ as to obtain various error messages which imply that the wrapper
+ really did engage.
+
+ Any regressions shown up by this program are potentially serious
+ and should be investigated carefully. */
+
+/* Needed for older glibcs (2.3 and older, at least) who don't
+ otherwise "know" about some more exotic pthread stuff, in this case
+ PTHREAD_MUTEX_ERRORCHECK. */
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+short unprotected = 0;
+
+void* lazy_child ( void* v ) {
+ assert(0); /* does not run */
+}
+
+void* racy_child ( void* v ) {
+ unprotected = 1234;
+ return NULL;
+}
+
+int main ( void )
+{
+ int r;
+ /* pthread_t thr; */
+ /* pthread_attr_t thra; */
+ pthread_mutexattr_t mxa, mxa2;
+ pthread_mutex_t mx, mx2, mx3, mx4;
+ pthread_cond_t cv;
+ struct timespec abstime;
+ pthread_rwlock_t rwl;
+ pthread_rwlock_t rwl2;
+ pthread_rwlock_t rwl3;
+ sem_t s1;
+
+ /* --------- pthread_create/join --------- */
+
+ fprintf(stderr,
+ "\n---------------- pthread_create/join ----------------\n\n");
+
+ /* make pthread_create fail */
+ /* It's amazingly difficult to make pthread_create fail
+ without first soaking up all the machine's resources.
+ Instead, in order to demonstrate that it's really wrapped,
+ create a child thread, generate a race error, and join with it
+ again. */
+ /* This just segfaults:
+ memset( &thra, 0xFF, sizeof(thra) );
+ r= pthread_create( &thr, NULL, lazy_child, NULL ); assert(r);
+ */
+ { pthread_t child;
+ r= pthread_create( &child, NULL, racy_child, NULL ); assert(!r);
+ sleep(1); /* just to ensure parent thread reports race, not child */
+ unprotected = 5678;
+ r= pthread_join( child, NULL ); assert(!r);
+ }
+
+ /* make pthread_join fail */
+ r= pthread_join( pthread_self(), NULL ); assert(r);
+
+ /* --------- pthread_mutex_lock et al --------- */
+
+ fprintf(stderr,
+ "\n---------------- pthread_mutex_lock et al ----------------\n\n");
+
+ /* make pthread_mutex_init fail */
+ memset( &mxa, 0xFF, sizeof(mxa) );
+ r= pthread_mutex_init( &mx, &mxa ); assert(r);
+
+ /* make pthread_mutex_destroy fail */
+ r= pthread_mutex_init( &mx2, NULL ); assert(!r);
+ r= pthread_mutex_lock( &mx2 ); assert(!r);
+ r= pthread_mutex_destroy( &mx2 ); assert(r);
+
+ /* make pthread_mutex_lock fail */
+ memset( &mx3, 0xFF, sizeof(mx3) );
+ r= pthread_mutex_lock( &mx3 ); assert(r);
+
+ /* make pthread_mutex_trylock fail */
+ memset( &mx3, 0xFF, sizeof(mx3) );
+ r= pthread_mutex_trylock( &mx3 ); assert(r);
+
+ /* make pthread_mutex_timedlock fail */
+ memset( &abstime, 0, sizeof(abstime) );
+ memset( &mx3, 0xFF, sizeof(mx3) );
+ r= pthread_mutex_timedlock( &mx3, &abstime ); assert(r);
+
+ /* make pthread_mutex_unlock fail */
+ memset( &mx3, 0xFF, sizeof(mx3) );
+ r= pthread_mutex_unlock( &mx3 ); assert(r);
+
+ /* --------- pthread_cond_wait et al --------- */
+
+ fprintf(stderr,
+ "\n---------------- pthread_cond_wait et al ----------------\n\n");
+
+ /* make pthread_cond_wait fail. This is difficult. Our cunning
+ plan (tm) is to show up at pthread_cond_wait bearing a
+ not-locked mutex of the ERRORCHECK flavour and hope (as is
+ indeed the case with glibc-2.5) that pthread_cond_wait notices
+ it is not locked, and bounces our request. */
+ r= pthread_mutexattr_init( &mxa2 ); assert(!r);
+ r= pthread_mutexattr_settype( &mxa2, PTHREAD_MUTEX_ERRORCHECK );
+ assert(!r);
+ r= pthread_mutex_init( &mx4, &mxa2 ); assert(!r);
+ r= pthread_cond_init( &cv, NULL ); assert(!r);
+ r= pthread_cond_wait( &cv, &mx4 ); assert(r);
+ r= pthread_mutexattr_destroy( &mxa2 ); assert(!r);
+
+ /* make pthread_cond_signal fail. FIXME: can't figure out how
+ to */
+ r= pthread_cond_signal( &cv ); assert(!r);
+ fprintf(stderr, "\nFIXME: can't figure out how to "
+ "verify wrap of pthread_cond_signal\n\n");
+
+ /* make pthread_cond_broadcast fail. FIXME: can't figure out how
+ to */
+ r= pthread_cond_broadcast( &cv ); assert(!r);
+ fprintf(stderr, "\nFIXME: can't figure out how to "
+ "verify wrap of pthread_broadcast_signal\n\n");
+
+ /* make pthread_cond_timedwait fail. */
+ memset( &abstime, 0, sizeof(abstime) );
+ abstime.tv_nsec = 1000000000 + 1;
+ r= pthread_cond_timedwait( &cv, &mx4, &abstime ); assert(r);
+
+ /* --------- pthread_rwlock_* --------- */
+
+ fprintf(stderr,
+ "\n---------------- pthread_rwlock_* ----------------\n\n");
+
+ /* pthread_rwlock_init, pthread_rwlock_unlock */
+ /* pthread_rwlock_init: can't make glibc's implementation fail.
+ However, can demonstrate interceptedness by initialising but not
+ locking a lock and then unlocking it. Then the unlock call
+ should say "first seen at .. the init call." So this tests
+ wrappedness of both calls. */
+ r= pthread_rwlock_init( &rwl, NULL ); assert(!r);
+ r= pthread_rwlock_unlock( &rwl );
+ /* assert(r); *//* glibc doesn't complain. It really ought to. Oh well. */
+
+ /* We can infer the presence of wrapping for pthread_rwlock_rdlock,
+ pthread_rwlock_wrlock and pthread_rwlock_unlock by making
+ Thrcheck count the lockedness state, and warning when we unlock
+ a not-locked lock. Thusly: */
+ r= pthread_rwlock_init( &rwl2, NULL ); assert(!r);
+
+ /* w-lock it */
+ fprintf(stderr, "(1) no error on next line\n");
+ r= pthread_rwlock_wrlock( &rwl2 ); assert(!r);
+ /* unlock it */
+ fprintf(stderr, "(2) no error on next line\n");
+ r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
+ /* unlock it again, get an error */
+ fprintf(stderr, "(3) ERROR on next line\n");
+ r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
+
+ /* same game with r-locks */
+ r= pthread_rwlock_init( &rwl2, NULL ); assert(!r);
+ /* r-lock it twice */
+ fprintf(stderr, "(4) no error on next line\n");
+ r= pthread_rwlock_rdlock( &rwl2 ); assert(!r);
+ fprintf(stderr, "(5) no error on next line\n");
+ r= pthread_rwlock_rdlock( &rwl2 ); assert(!r);
+ /* unlock it twice */
+ fprintf(stderr, "(6) no error on next line\n");
+ r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
+ fprintf(stderr, "(7) no error on next line\n");
+ r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
+ /* unlock it again, get an error */
+ fprintf(stderr, "(8) ERROR on next line\n");
+ r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
+
+ /* Lock rwl3 so the locked-lock-at-dealloc check can complain about
+ it. */
+ r= pthread_rwlock_init( &rwl3, NULL ); assert(!r);
+ r= pthread_rwlock_rdlock( &rwl3 ); assert(!r);
+
+ /* ------------- sem_* ------------- */
+
+ /* This is pretty lame, and duplicates tc18_semabuse.c. */
+
+ fprintf(stderr,
+ "\n---------------- sem_* ----------------\n\n");
+
+ /* verifies wrap of sem_init */
+ /* Do sem_init with huge initial count - fails */
+ r= sem_init(&s1, 0, ~0); assert(r);
+
+ /* initialise properly */
+ r= sem_init(&s1, 0, 0);
+
+ /* in glibc, sem_destroy is a no-op; making it fail is
+ impossible. */
+ fprintf(stderr, "\nFIXME: can't figure out how to verify wrap of "
+ "sem_destroy\n\n");
+
+ /* verifies wrap of sem_wait */
+ /* Do 'wait' on a bogus semaphore. This should fail, but on glibc
+ it succeeds. */
+ memset(&s1, 0x55, sizeof(s1));
+ r= sem_wait(&s1); /* assert(r != 0); */
+
+ /* this really ought to fail, but it doesn't. */
+ r= sem_post(&s1); assert(!r);
+ fprintf(stderr, "\nFIXME: can't figure out how to verify wrap of "
+ "sem_post\n\n");
+
+ sem_destroy(&s1);
+
+ /* ------------- dealloc of mem holding locks ------------- */
+
+ fprintf(stderr,
+ "\n------------ dealloc of mem holding locks ------------\n\n");
+
+ /* At this point it should complain about deallocation
+ of memory containing locked locks:
+ mx4
+ rwl3
+ */
+
+ return 0;
+}
Added: branches/THRCHECK/thrcheck/tests/tc20_verifywrap.stderr.exp-glibc25-amd64
===================================================================
--- branches/THRCHECK/thrcheck/tests/tc20_verifywrap.stderr.exp-glibc25-amd64 (rev 0)
+++ branches/THRCHECK/thrcheck/tests/tc20_verifywrap.stderr.exp-glibc25-amd64 2007-10-30 19:08:01 UTC (rev 7056)
@@ -0,0 +1,158 @@
+
+
+---------------- pthread_create/join ----------------
+
+Thread #1 is the program's root thread
+
+Thread #2 was created
+ at 0x........: clone (in /...libc...)
+ by 0x........: ...
+ by 0x........: pthread_create@GLIBC_ (in /lib/libpthread...)
+ by 0x........: pthread_create@* (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:64)
+
+Possible data race during write of size 2 at 0x........
+ at 0x........: main (tc20_verifywrap.c:66)
+ Old state: owned exclusively by thread #2
+ New state: shared-modified by threads #1, #2
+ Reason: this thread, #1, holds no locks at all
+
+Thread #1's call to pthread_join failed
+ with error code 35 (EDEADLK: Resource deadlock would occur)
+ at 0x........: pthread_join (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:71)
+
+---------------- pthread_mutex_lock et al ----------------
+
+
+Thread #1's call to pthread_mutex_init failed
+ with error code 95 (EOPNOTSUPP: Operation not supported on transport endpoint)
+ at 0x........: pthread_mutex_init (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:80)
+
+Thread #1: pthread_mutex_destroy of a locked mutex
+ at 0x........: pthread_mutex_destroy (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:85)
+
+Thread #1's call to pthread_mutex_destroy failed
+ with error code 16 (EBUSY: Device or resource busy)
+ at 0x........: pthread_mutex_destroy (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:85)
+
+Thread #1's call to pthread_mutex_lock failed
+ with error code 22 (EINVAL: Invalid argument)
+ at 0x........: pthread_mutex_lock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:89)
+
+Thread #1's call to pthread_mutex_trylock failed
+ with error code 22 (EINVAL: Invalid argument)
+ at 0x........: pthread_mutex_trylock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:93)
+
+Thread #1's call to pthread_mutex_timedlock failed
+ with error code 22 (EINVAL: Invalid argument)
+ at 0x........: pthread_mutex_timedlock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:98)
+
+Thread #1 unlocked an invalid lock at 0x........
+ at 0x........: pthread_mutex_unlock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:102)
+
+Thread #1's call to pthread_mutex_unlock failed
+ with error code 22 (EINVAL: Invalid argument)
+ at 0x........: pthread_mutex_unlock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:102)
+
+---------------- pthread_cond_wait et al ----------------
+
+
+Thread #1 unlocked a not-locked lock at 0x........
+ at 0x........: pthread_cond_wait@* (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:119)
+ Lock at 0x........ was first observed
+ at 0x........: pthread_mutex_init (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:117)
+
+Thread #1's call to pthread_cond_wait failed
+ with error code 1 (EPERM: Operation not permitted)
+ at 0x........: pthread_cond_wait@* (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:119)
+
+FIXME: can't figure out how to verify wrap of pthread_cond_signal
+
+
+FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
+
+
+Thread #1's call to pthread_cond_timedwait failed
+ with error code 22 (EINVAL: Invalid argument)
+ at 0x........: pthread_cond_timedwait@* (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:137)
+
+---------------- pthread_rwlock_* ----------------
+
+
+Thread #1 unlocked a not-locked lock at 0x........
+ at 0x........: pthread_rwlock_unlock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:151)
+ Lock at 0x........ was first observed
+ at 0x........: pthread_rwlock_init (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:150)
+(1) no error on next line
+(2) no error on next line
+(3) ERROR on next line
+
+Thread #1 unlocked a not-locked lock at 0x........
+ at 0x........: pthread_rwlock_unlock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:168)
+ Lock at 0x........ was first observed
+ at 0x........: pthread_rwlock_init (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:158)
+(4) no error on next line
+(5) no error on next line
+(6) no error on next line
+(7) no error on next line
+(8) ERROR on next line
+
+Thread #1 unlocked a not-locked lock at 0x........
+ at 0x........: pthread_rwlock_unlock (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:184)
+ Lock at 0x........ was first observed
+ at 0x........: pthread_rwlock_init (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:158)
+
+---------------- sem_* ----------------
+
+
+Thread #1's call to sem_init failed
+ with error code 22 (EINVAL: Invalid argument)
+ at 0x........: sem_init@* (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:200)
+
+FIXME: can't figure out how to verify wrap of sem_destroy
+
+
+Thread #1: Bug in libpthread: sem_wait succeeded on semaphore without prior sem_post
+ at 0x........: sem_wait_WRK (tc_intercepts.c:...)
+ by 0x........: sem_wait (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:214)
+
+FIXME: can't figure out how to verify wrap of sem_post
+
+
+------------ dealloc of mem holding locks ------------
+
+
+Thread #1 deallocated location 0x........ containing a locked lock
+ at 0x........: main (tc20_verifywrap.c:235)
+ Lock at 0x........ was first observed
+ at 0x........: pthread_rwlock_init (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:188)
+
+Thread #1 deallocated location 0x........ containing a locked lock
+ at 0x........: main (tc20_verifywrap.c:235)
+ Lock at 0x........ was first observed
+ at 0x........: pthread_mutex_init (tc_intercepts.c:...)
+ by 0x........: main (tc20_verifywrap.c:117)
+
+ERROR SUMMARY: 20 errors from 20 contexts (suppressed: 0 from 0)
Added: branches/THRCHECK/thrcheck/tests/tc20_verifywrap.stdout.exp
===================================================================
Added: branches/THRCHECK/thrcheck/tests/tc20_verifywrap.vgtest
===================================================================
--- branches/THRCHECK/thrcheck/tests/tc20_verifywrap.vgtest (rev 0)
+++ branches/THRCHECK/thrcheck/tests/tc20_verifywrap.vgtest 2007-10-30 19:08:01 UTC (rev 7056)
@@ -0,0 +1 @@
+prog: tc20_verifywrap
|