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