Home | History | Annotate | Download | only in tests
      1 /* This program attempts to verify that all functions that are
      2    supposed to be wrapped by tc_intercepts.c really are wrapped.  The
      3    main way it does this is to cause failures in those functions, so
      4    as to obtain various error messages which imply that the wrapper
      5    really did engage.
      6 
      7    Any regressions shown up by this program are potentially serious
      8    and should be investigated carefully. */
      9 
     10 /* Needed for older glibcs (2.3 and older, at least) who don't
     11    otherwise "know" about some more exotic pthread stuff, in this case
     12    PTHREAD_MUTEX_ERRORCHECK. */
     13 #define _GNU_SOURCE 1
     14 #include <stdio.h>
     15 #include <string.h>
     16 #include <assert.h>
     17 #include <unistd.h>
     18 #include "safe-pthread.h"
     19 #include "safe-semaphore.h"
     20 
     21 #if !defined(__APPLE__)
     22 
     23 #if defined(__sun__)
     24 /* Fake __GLIBC_PREREQ on Solaris. Pretend glibc >= 2.4. */
     25 # define __GLIBC_PREREQ
     26 #else
     27 #if !defined(__GLIBC_PREREQ)
     28 # error "This program needs __GLIBC_PREREQ (in /usr/include/features.h)"
     29 #endif
     30 #endif /* __sun__ */
     31 
     32 typedef union {
     33    pthread_spinlock_t spinlock;
     34    pthread_rwlock_t rwlock;
     35 } spin_rw_lock;
     36 
     37 short unprotected = 0;
     38 
     39 void* lazy_child ( void* v ) {
     40    assert(0); /* does not run */
     41 }
     42 
     43 void* racy_child ( void* v ) {
     44    unprotected = 1234;
     45    return NULL;
     46 }
     47 
     48 int main ( void )
     49 {
     50    int r;
     51    /* pthread_t thr; */
     52    /* pthread_attr_t thra; */
     53    pthread_mutexattr_t mxa, mxa2;
     54    pthread_mutex_t mx, mx2, mx3, mx4;
     55    pthread_cond_t cv;
     56    struct timespec abstime;
     57    pthread_rwlock_t rwl;
     58    pthread_rwlock_t rwl2;
     59    pthread_rwlock_t rwl3;
     60    sem_t s1;
     61 
     62 #  if __GLIBC_PREREQ(2,4)
     63    fprintf(stderr,
     64            "\n\n------ This is output for >= glibc 2.4 ------\n");
     65 #  else
     66    fprintf(stderr,
     67            "\n\n------ This is output for < glibc 2.4 ------\n");
     68 #  endif
     69 
     70    /* --------- pthread_create/join --------- */
     71 
     72    fprintf(stderr,
     73    "\n---------------- pthread_create/join ----------------\n\n");
     74 
     75    /* make pthread_create fail */
     76    /* It's amazingly difficult to make pthread_create fail
     77       without first soaking up all the machine's resources.
     78       Instead, in order to demonstrate that it's really wrapped,
     79       create a child thread, generate a race error, and join with it
     80       again. */
     81    /* This just segfaults:
     82       memset( &thra, 0xFF, sizeof(thra) );
     83       r= pthread_create( &thr, NULL, lazy_child, NULL ); assert(r);
     84    */
     85    { pthread_t child;
     86      r= pthread_create( &child, NULL, racy_child, NULL ); assert(!r);
     87      sleep(1); /* just to ensure parent thread reports race, not child */
     88      unprotected = 5678;
     89      r= pthread_join( child, NULL ); assert(!r);
     90    }
     91 
     92    /* make pthread_join fail */
     93    r= pthread_join( pthread_self(), NULL ); assert(r);
     94 
     95    /* --------- pthread_mutex_lock et al --------- */
     96 
     97    fprintf(stderr,
     98    "\n---------------- pthread_mutex_lock et al ----------------\n\n");
     99 
    100    /* make pthread_mutex_init fail */
    101 #if defined(__sun__)
    102    pthread_mutexattr_init( &mxa );
    103    memset( mxa.__pthread_mutexattrp, 0xFF, 5 * sizeof(int) );
    104 #else
    105    memset( &mxa, 0xFF, sizeof(mxa) );
    106 #endif
    107    r= pthread_mutex_init( &mx, &mxa );
    108 #  if __GLIBC_PREREQ(2,4)
    109    assert(r); /* glibc >= 2.4: the call should fail */
    110 #  else
    111    assert(!r); /* glibc < 2.4: oh well, glibc didn't bounce this */
    112 #  endif
    113 
    114    /* make pthread_mutex_destroy fail */
    115    r= pthread_mutex_init( &mx2, NULL ); assert(!r);
    116    r= pthread_mutex_lock( &mx2 ); assert(!r);
    117    r= pthread_mutex_destroy( &mx2 );
    118 
    119    /* make pthread_mutex_lock fail (skipped on < glibc 2.4 because it
    120       doesn't fail, hence hangs the test) */
    121 #  if __GLIBC_PREREQ(2,4)
    122    memset( &mx3, 0xFF, sizeof(mx3) );
    123    r= pthread_mutex_lock( &mx3 ); assert(r);
    124 #  else
    125    fprintf(stderr, "\nmake pthread_mutex_lock fail: "
    126                    "skipped on glibc < 2.4\n\n");
    127 #  endif
    128 
    129    /* make pthread_mutex_trylock fail */
    130    memset( &mx3, 0xFF, sizeof(mx3) );
    131    r= pthread_mutex_trylock( &mx3 ); assert(r);
    132 
    133    /* make pthread_mutex_timedlock fail */
    134    memset( &abstime, 0, sizeof(abstime) );
    135    memset( &mx3, 0xFF, sizeof(mx3) );
    136    r= pthread_mutex_timedlock( &mx3, &abstime ); assert(r);
    137 
    138    /* make pthread_mutex_unlock fail */
    139    memset( &mx3, 0xFF, sizeof(mx3) );
    140    r= pthread_mutex_unlock( &mx3 );
    141 #  if __GLIBC_PREREQ(2,4)
    142    assert(r);
    143 #  else
    144    assert(!r);
    145 #  endif
    146 
    147    /* --------- pthread_cond_wait et al --------- */
    148 
    149    fprintf(stderr,
    150    "\n---------------- pthread_cond_wait et al ----------------\n\n");
    151 
    152    /* make pthread_cond_wait fail.  This is difficult.  Our cunning
    153       plan (tm) is to show up at pthread_cond_wait bearing a
    154       not-locked mutex of the ERRORCHECK flavour and hope (as is
    155       indeed the case with glibc-2.5) that pthread_cond_wait notices
    156       it is not locked, and bounces our request. */
    157    r= pthread_mutexattr_init( &mxa2 ); assert(!r);
    158    r= pthread_mutexattr_settype( &mxa2, PTHREAD_MUTEX_ERRORCHECK );
    159       assert(!r);
    160    r= pthread_mutex_init( &mx4, &mxa2 ); assert(!r);
    161    r= pthread_cond_init( &cv, NULL ); assert(!r);
    162    r= pthread_cond_wait( &cv, &mx4 ); assert(r);
    163    r= pthread_mutexattr_destroy( &mxa2 ); assert(!r);
    164 
    165    /* make pthread_cond_signal fail.  FIXME: can't figure out how
    166       to */
    167    r= pthread_cond_signal( &cv ); assert(!r);
    168    fprintf(stderr, "\nFIXME: can't figure out how to "
    169                    "verify wrap of pthread_cond_signal\n\n");
    170 
    171    /* make pthread_cond_broadcast fail.  FIXME: can't figure out how
    172       to */
    173    r= pthread_cond_broadcast( &cv ); assert(!r);
    174    fprintf(stderr, "\nFIXME: can't figure out how to "
    175                    "verify wrap of pthread_broadcast_signal\n\n");
    176 
    177    /* make pthread_cond_timedwait fail. */
    178    memset( &abstime, 0, sizeof(abstime) );
    179    abstime.tv_nsec = 1000000000 + 1;
    180    r= pthread_cond_timedwait( &cv, &mx4, &abstime ); assert(r);
    181 
    182    /* --------- pthread_rwlock_* --------- */
    183 
    184    fprintf(stderr,
    185    "\n---------------- pthread_rwlock_* ----------------\n\n");
    186 
    187    /* pthread_rwlock_init, pthread_rwlock_unlock */
    188    /* pthread_rwlock_init: can't make glibc's implementation fail.
    189       However, can demonstrate interceptedness by initialising but not
    190       locking a lock and then unlocking it.  Then the unlock call
    191       should say "first seen at .. the init call."  So this tests
    192       wrappedness of both calls. */
    193    r= pthread_rwlock_init( &rwl, NULL ); assert(!r);
    194    r= pthread_rwlock_unlock( &rwl );
    195    /* assert(r); *//* glibc doesn't complain.  It really ought to. Oh well. */
    196 
    197    /* We can infer the presence of wrapping for pthread_rwlock_rdlock,
    198       pthread_rwlock_wrlock and pthread_rwlock_unlock by making
    199       Thrcheck count the lockedness state, and warning when we unlock
    200       a not-locked lock.  Thusly: */
    201    r= pthread_rwlock_init( &rwl2, NULL ); assert(!r);
    202 
    203    /* w-lock it */
    204    fprintf(stderr, "(1) no error on next line\n");
    205    r= pthread_rwlock_wrlock( &rwl2 ); assert(!r);
    206    /* unlock it */
    207    fprintf(stderr, "(2) no error on next line\n");
    208    r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
    209    /* unlock it again, get an error */
    210    fprintf(stderr, "(3)    ERROR on next line\n");
    211    r= pthread_rwlock_unlock( &rwl2 );
    212 #if defined(__sun__)
    213    assert(r);
    214 #else
    215    assert(!r);
    216 #endif
    217 
    218    /* same game with r-locks */
    219    r= pthread_rwlock_init( &rwl2, NULL ); assert(!r);
    220    /* r-lock it twice */
    221    fprintf(stderr, "(4) no error on next line\n");
    222    r= pthread_rwlock_rdlock( &rwl2 ); assert(!r);
    223    fprintf(stderr, "(5) no error on next line\n");
    224    r= pthread_rwlock_rdlock( &rwl2 ); assert(!r);
    225    /* unlock it twice */
    226    fprintf(stderr, "(6) no error on next line\n");
    227    r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
    228    fprintf(stderr, "(7) no error on next line\n");
    229    r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
    230    /* unlock it again, get an error */
    231    fprintf(stderr, "(8)    ERROR on next line\n");
    232    r= pthread_rwlock_unlock( &rwl2 );
    233 #if defined(__sun__)
    234    assert(r);
    235 #else
    236    assert(!r);
    237 #endif
    238 
    239    /* Lock rwl3 so the locked-lock-at-dealloc check can complain about
    240       it. */
    241    r= pthread_rwlock_init( &rwl3, NULL ); assert(!r);
    242    r= pthread_rwlock_rdlock( &rwl3 ); assert(!r);
    243 
    244    /* --------- pthread_spin_* --------- */
    245 
    246    fprintf(stderr,
    247    "\n---------------- pthread_spin_* ----------------\n\n");
    248 
    249    /* The following sequence verifies correct wrapping of pthread_spin_init()
    250       and pthread_spin_destroy(). */
    251    spin_rw_lock srwl1;
    252    pthread_spin_init(&srwl1.spinlock, PTHREAD_PROCESS_PRIVATE);
    253    pthread_spin_destroy(&srwl1.spinlock);
    254 
    255    pthread_rwlock_init(&srwl1.rwlock, NULL);
    256    pthread_rwlock_destroy(&srwl1.rwlock);
    257 
    258    /* ------------- sem_* ------------- */
    259 
    260    /* This is pretty lame, and duplicates tc18_semabuse.c. */
    261 
    262    fprintf(stderr,
    263    "\n---------------- sem_* ----------------\n\n");
    264 
    265    /* verifies wrap of sem_init */
    266    /* Do sem_init with huge initial count - fails */
    267    r= sem_init(&s1, 0, ~0); assert(r);
    268 
    269    /* initialise properly */
    270    r= sem_init(&s1, 0, 0);
    271 
    272    /* in glibc, sem_destroy is a no-op; making it fail is
    273       impossible. */
    274    fprintf(stderr, "\nFIXME: can't figure out how to verify wrap of "
    275                    "sem_destroy\n\n");
    276 
    277    /* verifies wrap of sem_wait */
    278    /* Do 'wait' on a bogus semaphore.  This should fail, but on glibc
    279       it succeeds. */
    280    memset(&s1, 0x55, sizeof(s1));
    281    r= sem_wait(&s1); /* assert(r != 0); */
    282 
    283    /* this only fails with glibc 2.7 or later. */
    284    r= sem_post(&s1);
    285    fprintf(stderr, "\nFIXME: can't figure out how to verify wrap of "
    286                    "sem_post\n\n");
    287 
    288    sem_destroy(&s1);
    289 
    290    /* ------------- dealloc of mem holding locks ------------- */
    291 
    292    fprintf(stderr,
    293    "\n------------ dealloc of mem holding locks ------------\n\n");
    294 
    295    /* At this point it should complain about deallocation
    296       of memory containing locked locks:
    297          rwl3
    298    */
    299 
    300    return 0;
    301 }
    302 
    303 #else /* defined(__APPLE__) */
    304 int main ( void )
    305 {
    306    fprintf(stderr, "This program does not work on Mac OS X.\n");
    307    return 0;
    308 }
    309 #endif
    310