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