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
7 Any regressions shown up by this program are potentially serious
8 and should be investigated carefully. */
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. */
18 #include "safe-pthread.h"
19 #include "safe-semaphore.h"
21 #if !defined(__APPLE__)
24 /* Fake __GLIBC_PREREQ on Solaris. Pretend glibc >= 2.4. */
25 # define __GLIBC_PREREQ
27 #if !defined(__GLIBC_PREREQ)
28 # error "This program needs __GLIBC_PREREQ (in /usr/include/features.h)"
33 pthread_spinlock_t spinlock
;
34 pthread_rwlock_t rwlock
;
37 short unprotected
= 0;
39 void* lazy_child ( void* v
) {
40 assert(0); /* does not run */
43 void* racy_child ( void* v
) {
52 /* pthread_attr_t thra; */
53 pthread_mutexattr_t mxa
, mxa2
;
54 pthread_mutex_t mx
, mx2
, mx3
, mx4
;
56 struct timespec abstime
;
58 pthread_rwlock_t rwl2
;
59 pthread_rwlock_t rwl3
;
62 # if __GLIBC_PREREQ(2,4)
64 "\n\n------ This is output for >= glibc 2.4 ------\n");
67 "\n\n------ This is output for < glibc 2.4 ------\n");
70 /* --------- pthread_create/join --------- */
73 "\n---------------- pthread_create/join ----------------\n\n");
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
81 /* This just segfaults:
82 memset( &thra, 0xFF, sizeof(thra) );
83 r= pthread_create( &thr, NULL, lazy_child, NULL ); assert(r);
86 r
= pthread_create( &child
, NULL
, racy_child
, NULL
); assert(!r
);
87 sleep(1); /* just to ensure parent thread reports race, not child */
89 r
= pthread_join( child
, NULL
); assert(!r
);
92 /* make pthread_join fail */
93 r
= pthread_join( pthread_self(), NULL
); assert(r
);
95 /* --------- pthread_mutex_lock et al --------- */
98 "\n---------------- pthread_mutex_lock et al ----------------\n\n");
100 /* make pthread_mutex_init fail */
102 pthread_mutexattr_init( &mxa
);
103 memset( mxa
.__pthread_mutexattrp
, 0xFF, 5 * sizeof(int) );
105 memset( &mxa
, 0xFF, sizeof(mxa
) );
107 r
= pthread_mutex_init( &mx
, &mxa
);
108 # if __GLIBC_PREREQ(2,4)
109 assert(r
); /* glibc >= 2.4: the call should fail */
111 assert(!r
); /* glibc < 2.4: oh well, glibc didn't bounce this */
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
);
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
);
125 fprintf(stderr
, "\nmake pthread_mutex_lock fail: "
126 "skipped on glibc < 2.4\n\n");
129 /* make pthread_mutex_trylock fail */
130 memset( &mx3
, 0xFF, sizeof(mx3
) );
131 r
= pthread_mutex_trylock( &mx3
); assert(r
);
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
);
138 /* make pthread_mutex_unlock fail */
139 memset( &mx3
, 0xFF, sizeof(mx3
) );
140 r
= pthread_mutex_unlock( &mx3
);
141 # if __GLIBC_PREREQ(2,4)
147 /* --------- pthread_cond_wait et al --------- */
150 "\n---------------- pthread_cond_wait et al ----------------\n\n");
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
);
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
);
165 /* make pthread_cond_signal fail. FIXME: can't figure out how
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");
171 /* make pthread_cond_broadcast fail. FIXME: can't figure out how
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");
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
);
182 /* --------- pthread_rwlock_* --------- */
185 "\n---------------- pthread_rwlock_* ----------------\n\n");
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. */
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
);
204 fprintf(stderr
, "(1) no error on next line\n");
205 r
= pthread_rwlock_wrlock( &rwl2
); assert(!r
);
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
);
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
);
239 /* Lock rwl3 so the locked-lock-at-dealloc check can complain about
241 r
= pthread_rwlock_init( &rwl3
, NULL
); assert(!r
);
242 r
= pthread_rwlock_rdlock( &rwl3
); assert(!r
);
244 /* --------- pthread_spin_* --------- */
247 "\n---------------- pthread_spin_* ----------------\n\n");
249 /* The following sequence verifies correct wrapping of pthread_spin_init()
250 and pthread_spin_destroy(). */
252 pthread_spin_init(&srwl1
.spinlock
, PTHREAD_PROCESS_PRIVATE
);
253 pthread_spin_destroy(&srwl1
.spinlock
);
255 pthread_rwlock_init(&srwl1
.rwlock
, NULL
);
256 pthread_rwlock_destroy(&srwl1
.rwlock
);
258 /* ------------- sem_* ------------- */
260 /* This is pretty lame, and duplicates tc18_semabuse.c. */
263 "\n---------------- sem_* ----------------\n\n");
265 /* verifies wrap of sem_init */
266 /* Do sem_init with huge initial count - fails */
267 r
= sem_init(&s1
, 0, ~0); assert(r
);
269 /* initialise properly */
270 r
= sem_init(&s1
, 0, 0);
272 /* in glibc, sem_destroy is a no-op; making it fail is
274 fprintf(stderr
, "\nFIXME: can't figure out how to verify wrap of "
277 /* verifies wrap of sem_wait */
278 /* Do 'wait' on a bogus semaphore. This should fail, but on glibc
280 memset(&s1
, 0x55, sizeof(s1
));
281 r
= sem_wait(&s1
); /* assert(r != 0); */
283 /* this only fails with glibc 2.7 or later. */
285 fprintf(stderr
, "\nFIXME: can't figure out how to verify wrap of "
290 /* ------------- dealloc of mem holding locks ------------- */
293 "\n------------ dealloc of mem holding locks ------------\n\n");
295 /* At this point it should complain about deallocation
296 of memory containing locked locks:
303 #else /* defined(__APPLE__) */
306 fprintf(stderr
, "This program does not work on Mac OS X.\n");