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
lazy_child(void * v)29 void* lazy_child ( void* v ) {
30 assert(0); /* does not run */
31 }
32
racy_child(void * v)33 void* racy_child ( void* v ) {
34 unprotected = 1234;
35 return NULL;
36 }
37
main(void)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__) */
main(void)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