• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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