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