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