blob: db4696207c4f832b2b6fd797620f0673e09de704 [file] [log] [blame]
sewardjb4112022007-11-09 22:49:28 +00001
2/*--------------------------------------------------------------------*/
3/*--- pthread intercepts for thread checking. ---*/
4/*--- tc_intercepts.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
sewardj4d474d02008-02-11 11:34:59 +000011 Copyright (C) 2007-2008 OpenWorks LLP
sewardjb4112022007-11-09 22:49:28 +000012 info@open-works.co.uk
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
35*/
36
37/* RUNS ON SIMULATED CPU
38 Interceptors for pthread_* functions, so that tc_main can see
39 significant thread events.
40
41 Important: when adding a function wrapper to this file, remember to
42 add a test case to tc20_verifywrap.c. A common cause of failure is
43 for wrappers to not engage on different distros, and
44 tc20_verifywrap essentially checks that each wrapper is really
45 doing something.
46*/
47
48#include "pub_tool_basics.h"
sewardj38e0cf92008-11-19 10:40:56 +000049#include "pub_tool_redir.h"
sewardjb4112022007-11-09 22:49:28 +000050#include "valgrind.h"
51#include "helgrind.h"
52
53#define TRACE_PTH_FNS 0
54#define TRACE_QT4_FNS 0
55
56
57/*----------------------------------------------------------------*/
58/*--- ---*/
59/*----------------------------------------------------------------*/
60
61#define PTH_FUNC(ret_ty, f, args...) \
62 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libpthreadZdsoZd0,f)(args); \
63 ret_ty I_WRAP_SONAME_FNNAME_ZZ(libpthreadZdsoZd0,f)(args)
64
65// Do a client request. This is a macro rather than a function
66// so as to avoid having an extra function in the stack trace.
67
68#define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
69 do { \
70 Word _unused_res, _arg1; \
71 assert(sizeof(_ty1F) == sizeof(Word)); \
72 _arg1 = (Word)(_arg1F); \
73 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \
74 (_creqF), \
75 _arg1, 0,0,0,0); \
76 } while (0)
77
78#define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
79 do { \
80 Word _unused_res, _arg1, _arg2; \
81 assert(sizeof(_ty1F) == sizeof(Word)); \
82 assert(sizeof(_ty2F) == sizeof(Word)); \
83 _arg1 = (Word)(_arg1F); \
84 _arg2 = (Word)(_arg2F); \
85 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \
86 (_creqF), \
87 _arg1,_arg2,0,0,0); \
88 } while (0)
89
90#define DO_CREQ_W_WW(_resF, _creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
91 do { \
92 Word _res, _arg1, _arg2; \
93 assert(sizeof(_ty1F) == sizeof(Word)); \
94 assert(sizeof(_ty2F) == sizeof(Word)); \
95 _arg1 = (Word)(_arg1F); \
96 _arg2 = (Word)(_arg2F); \
97 VALGRIND_DO_CLIENT_REQUEST(_res, 2, \
98 (_creqF), \
99 _arg1,_arg2,0,0,0); \
100 _resF = _res; \
101 } while (0)
102
103#define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
104 _ty2F,_arg2F, _ty3F, _arg3F) \
105 do { \
106 Word _unused_res, _arg1, _arg2, _arg3; \
107 assert(sizeof(_ty1F) == sizeof(Word)); \
108 assert(sizeof(_ty2F) == sizeof(Word)); \
109 assert(sizeof(_ty3F) == sizeof(Word)); \
110 _arg1 = (Word)(_arg1F); \
111 _arg2 = (Word)(_arg2F); \
112 _arg3 = (Word)(_arg3F); \
113 VALGRIND_DO_CLIENT_REQUEST(_unused_res, 0, \
114 (_creqF), \
115 _arg1,_arg2,_arg3,0,0); \
116 } while (0)
117
118
119#define DO_PthAPIerror(_fnnameF, _errF) \
120 do { \
121 char* _fnname = (char*)(_fnnameF); \
122 long _err = (long)(int)(_errF); \
123 char* _errstr = lame_strerror(_err); \
124 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTH_API_ERROR, \
125 char*,_fnname, \
126 long,_err, char*,_errstr); \
127 } while (0)
128
129
130/* Needed for older glibcs (2.3 and older, at least) who don't
131 otherwise "know" about pthread_rwlock_anything or about
132 PTHREAD_MUTEX_RECURSIVE (amongst things). */
133#define _GNU_SOURCE 1
134
135#include <stdio.h>
136#include <assert.h>
137#include <errno.h>
138#include <pthread.h>
139
140
141/* A lame version of strerror which doesn't use the real libc
142 strerror_r, since using the latter just generates endless more
143 threading errors (glibc goes off and does tons of crap w.r.t.
144 locales etc) */
145static char* lame_strerror ( long err )
146{ switch (err) {
147 case EPERM: return "EPERM: Operation not permitted";
148 case ENOENT: return "ENOENT: No such file or directory";
149 case ESRCH: return "ESRCH: No such process";
150 case EINTR: return "EINTR: Interrupted system call";
151 case EBADF: return "EBADF: Bad file number";
152 case EAGAIN: return "EAGAIN: Try again";
153 case ENOMEM: return "ENOMEM: Out of memory";
154 case EACCES: return "EACCES: Permission denied";
155 case EFAULT: return "EFAULT: Bad address";
156 case EEXIST: return "EEXIST: File exists";
157 case EINVAL: return "EINVAL: Invalid argument";
158 case EMFILE: return "EMFILE: Too many open files";
159 case ENOSYS: return "ENOSYS: Function not implemented";
160 case EOVERFLOW: return "EOVERFLOW: Value too large "
161 "for defined data type";
162 case EBUSY: return "EBUSY: Device or resource busy";
163 case ETIMEDOUT: return "ETIMEDOUT: Connection timed out";
164 case EDEADLK: return "EDEADLK: Resource deadlock would occur";
165 case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on "
166 "transport endpoint"; /* honest, guv */
167 default: return "tc_intercepts.c: lame_strerror(): "
168 "unhandled case -- please fix me!";
169 }
170}
171
172
173/*----------------------------------------------------------------*/
174/*--- pthread_create, pthread_join, pthread_exit ---*/
175/*----------------------------------------------------------------*/
176
sewardj0d2a2c12007-11-11 05:58:41 +0000177/* Do not rename this function. It contains an unavoidable race and
178 so is mentioned by name in glibc-*helgrind*.supp. */
sewardjb4112022007-11-09 22:49:28 +0000179static void* mythread_wrapper ( void* xargsV )
180{
bart31277bf2008-07-29 17:04:31 +0000181 volatile Word* xargs = (volatile Word*) xargsV;
sewardjb4112022007-11-09 22:49:28 +0000182 void*(*fn)(void*) = (void*(*)(void*))xargs[0];
183 void* arg = (void*)xargs[1];
184 pthread_t me = pthread_self();
185 /* Tell the tool what my pthread_t is. */
186 DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
187 /* allow the parent to proceed. We can't let it proceed until
188 we're ready because (1) we need to make sure it doesn't exit and
189 hence deallocate xargs[] while we still need it, and (2) we
190 don't want either parent nor child to proceed until the tool has
191 been notified of the child's pthread_t. */
192 xargs[2] = 0;
193 /* Now we can no longer safely use xargs[]. */
194 return (void*) fn( (void*)arg );
195}
196
197// pthread_create
198PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
199 pthread_t *thread, const pthread_attr_t *attr,
200 void *(*start) (void *), void *arg)
201{
202 int ret;
203 OrigFn fn;
204 volatile Word xargs[3];
205
206 VALGRIND_GET_ORIG_FN(fn);
207 if (TRACE_PTH_FNS) {
208 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
209 }
210 xargs[0] = (Word)start;
211 xargs[1] = (Word)arg;
212 xargs[2] = 1; /* serves as a spinlock -- sigh */
213
214 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
215
216 if (ret == 0) {
217 /* we have to wait for the child to notify the tool of its
218 pthread_t before continuing */
219 while (xargs[2] != 0) {
sewardjeafad3b2007-11-18 01:16:52 +0000220 /* Do nothing. We need to spin until the child writes to
221 xargs[2]. However, that can lead to starvation in the
222 child and very long delays (eg, tc19_shadowmem on
223 ppc64-linux Fedora Core 6). So yield the cpu if we can,
224 to let the child run at the earliest available
225 opportunity. */
226 sched_yield();
sewardjb4112022007-11-09 22:49:28 +0000227 }
228 } else {
229 DO_PthAPIerror( "pthread_create", ret );
230 }
231
232 if (TRACE_PTH_FNS) {
233 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
234 }
235 return ret;
236}
237
238// pthread_join
239PTH_FUNC(int, pthreadZujoin, // pthread_join
240 pthread_t thread, void** value_pointer)
241{
242 int ret;
243 OrigFn fn;
244 VALGRIND_GET_ORIG_FN(fn);
245 if (TRACE_PTH_FNS) {
246 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
247 }
248
249 CALL_FN_W_WW(ret, fn, thread,value_pointer);
250
251 /* At least with NPTL as the thread library, this is safe because
252 it is guaranteed (by NPTL) that the joiner will completely gone
253 before pthread_join (the original) returns. See email below.*/
254 if (ret == 0 /*success*/) {
255 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
256 } else {
257 DO_PthAPIerror( "pthread_join", ret );
258 }
259
260 if (TRACE_PTH_FNS) {
261 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
262 }
263 return ret;
264}
265
266/* Behaviour of pthread_join on NPTL:
267
268Me:
269I have a question re the NPTL pthread_join implementation.
270
271 Suppose I am the thread 'stayer'.
272
273 If I call pthread_join(quitter), is it guaranteed that the
274 thread 'quitter' has really exited before pthread_join returns?
275
276 IOW, is it guaranteed that 'quitter' will not execute any further
277 instructions after pthread_join returns?
278
279I believe this is true based on the following analysis of
280glibc-2.5 sources. However am not 100% sure and would appreciate
281confirmation.
282
283 'quitter' will be running start_thread() in nptl/pthread_create.c
284
285 The last action of start_thread() is to exit via
286 __exit_thread_inline(0), which simply does sys_exit
287 (nptl/pthread_create.c:403)
288
289 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
290 (call at nptl/pthread_join.c:89)
291
292 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
293 lll_wait_tid will not return until kernel notifies via futex
294 wakeup that 'quitter' has terminated.
295
296 Hence pthread_join cannot return until 'quitter' really has
297 completely disappeared.
298
299Drepper:
300> As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
301> lll_wait_tid will not return until kernel notifies via futex
302> wakeup that 'quitter' has terminated.
303That's the key. The kernel resets the TID field after the thread is
304done. No way the joiner can return before the thread is gone.
305*/
306
307
308/*----------------------------------------------------------------*/
309/*--- pthread_mutex_t functions ---*/
310/*----------------------------------------------------------------*/
311
312/* Handled: pthread_mutex_init pthread_mutex_destroy
313 pthread_mutex_lock
314 pthread_mutex_trylock pthread_mutex_timedlock
315 pthread_mutex_unlock
316
317 Unhandled: pthread_spin_init pthread_spin_destroy
318 pthread_spin_lock
319 pthread_spin_trylock
320 pthread_spin_unlock
321*/
322
323// pthread_mutex_init
324PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
325 pthread_mutex_t *mutex,
326 pthread_mutexattr_t* attr)
327{
328 int ret;
329 long mbRec;
330 OrigFn fn;
331 VALGRIND_GET_ORIG_FN(fn);
332 if (TRACE_PTH_FNS) {
333 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
334 }
335
336 mbRec = 0;
337 if (attr) {
338 int ty, zzz;
339 zzz = pthread_mutexattr_gettype(attr, &ty);
340 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
341 mbRec = 1;
342 }
343
344 CALL_FN_W_WW(ret, fn, mutex,attr);
345
346 if (ret == 0 /*success*/) {
347 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
348 pthread_mutex_t*,mutex, long,mbRec);
349 } else {
350 DO_PthAPIerror( "pthread_mutex_init", ret );
351 }
352
353 if (TRACE_PTH_FNS) {
354 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
355 }
356 return ret;
357}
358
359
360// pthread_mutex_destroy
361PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
362 pthread_mutex_t *mutex)
363{
364 int ret;
365 OrigFn fn;
366 VALGRIND_GET_ORIG_FN(fn);
367 if (TRACE_PTH_FNS) {
368 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
369 }
370
371 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
372 pthread_mutex_t*,mutex);
373
374 CALL_FN_W_W(ret, fn, mutex);
375
376 if (ret != 0) {
377 DO_PthAPIerror( "pthread_mutex_destroy", ret );
378 }
379
380 if (TRACE_PTH_FNS) {
381 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
382 }
383 return ret;
384}
385
386
387// pthread_mutex_lock
388PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
389 pthread_mutex_t *mutex)
390{
391 int ret;
392 OrigFn fn;
393 VALGRIND_GET_ORIG_FN(fn);
394 if (TRACE_PTH_FNS) {
395 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
396 }
397
398 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
399 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
400
401 CALL_FN_W_W(ret, fn, mutex);
402
403 /* There's a hole here: libpthread now knows the lock is locked,
404 but the tool doesn't, so some other thread could run and detect
405 that the lock has been acquired by someone (this thread). Does
406 this matter? Not sure, but I don't think so. */
407
408 if (ret == 0 /*success*/) {
409 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
410 pthread_mutex_t*,mutex);
411 } else {
412 DO_PthAPIerror( "pthread_mutex_lock", ret );
413 }
414
415 if (TRACE_PTH_FNS) {
416 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
417 }
418 return ret;
419}
420
421
422// pthread_mutex_trylock. The handling needed here is very similar
423// to that for pthread_mutex_lock, except that we need to tell
424// the pre-lock creq that this is a trylock-style operation, and
425// therefore not to complain if the lock is nonrecursive and
426// already locked by this thread -- because then it'll just fail
427// immediately with EBUSY.
428PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
429 pthread_mutex_t *mutex)
430{
431 int ret;
432 OrigFn fn;
433 VALGRIND_GET_ORIG_FN(fn);
434 if (TRACE_PTH_FNS) {
435 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
436 }
437
438 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
439 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
440
441 CALL_FN_W_W(ret, fn, mutex);
442
443 /* There's a hole here: libpthread now knows the lock is locked,
444 but the tool doesn't, so some other thread could run and detect
445 that the lock has been acquired by someone (this thread). Does
446 this matter? Not sure, but I don't think so. */
447
448 if (ret == 0 /*success*/) {
449 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
450 pthread_mutex_t*,mutex);
451 } else {
452 if (ret != EBUSY)
453 DO_PthAPIerror( "pthread_mutex_trylock", ret );
454 }
455
456 if (TRACE_PTH_FNS) {
457 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
458 }
459 return ret;
460}
461
462
463// pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
464PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
465 pthread_mutex_t *mutex,
466 void* timeout)
467{
468 int ret;
469 OrigFn fn;
470 VALGRIND_GET_ORIG_FN(fn);
471 if (TRACE_PTH_FNS) {
472 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
473 fflush(stderr);
474 }
475
476 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
477 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
478
479 CALL_FN_W_WW(ret, fn, mutex,timeout);
480
481 /* There's a hole here: libpthread now knows the lock is locked,
482 but the tool doesn't, so some other thread could run and detect
483 that the lock has been acquired by someone (this thread). Does
484 this matter? Not sure, but I don't think so. */
485
486 if (ret == 0 /*success*/) {
487 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
488 pthread_mutex_t*,mutex);
489 } else {
490 if (ret != ETIMEDOUT)
491 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
492 }
493
494 if (TRACE_PTH_FNS) {
495 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
496 }
497 return ret;
498}
499
500
501// pthread_mutex_unlock
502PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
503 pthread_mutex_t *mutex)
504{
505 int ret;
506 OrigFn fn;
507 VALGRIND_GET_ORIG_FN(fn);
508
509 if (TRACE_PTH_FNS) {
510 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
511 }
512
513 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
514 pthread_mutex_t*,mutex);
515
516 CALL_FN_W_W(ret, fn, mutex);
517
518 if (ret == 0 /*success*/) {
519 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
520 pthread_mutex_t*,mutex);
521 } else {
522 DO_PthAPIerror( "pthread_mutex_unlock", ret );
523 }
524
525 if (TRACE_PTH_FNS) {
526 fprintf(stderr, " mxunlk -> %d >>\n", ret);
527 }
528 return ret;
529}
530
531
532/*----------------------------------------------------------------*/
533/*--- pthread_cond_t functions ---*/
534/*----------------------------------------------------------------*/
535
536/* Handled: pthread_cond_wait pthread_cond_timedwait
537 pthread_cond_signal pthread_cond_broadcast
sewardjf98e1c02008-10-25 16:22:41 +0000538 pthread_cond_destroy
sewardjb4112022007-11-09 22:49:28 +0000539
sewardjf98e1c02008-10-25 16:22:41 +0000540 Unhandled: pthread_cond_init
541 -- is this important?
sewardjb4112022007-11-09 22:49:28 +0000542*/
543
544// pthread_cond_wait
545PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
546 pthread_cond_t* cond, pthread_mutex_t* mutex)
547{
548 int ret;
549 OrigFn fn;
550 unsigned long mutex_is_valid;
551
552 VALGRIND_GET_ORIG_FN(fn);
553
554 if (TRACE_PTH_FNS) {
555 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
556 fflush(stderr);
557 }
558
559 /* Tell the tool a cond-wait is about to happen, so it can check
560 for bogus argument values. In return it tells us whether it
561 thinks the mutex is valid or not. */
562 DO_CREQ_W_WW(mutex_is_valid,
563 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
564 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
565 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
566
567 /* Tell the tool we're about to drop the mutex. This reflects the
568 fact that in a cond_wait, we show up holding the mutex, and the
569 call atomically drops the mutex and waits for the cv to be
570 signalled. */
571 if (mutex_is_valid) {
572 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
573 pthread_mutex_t*,mutex);
574 }
575
576 CALL_FN_W_WW(ret, fn, cond,mutex);
577
578 /* these conditionals look stupid, but compare w/ same logic for
579 pthread_cond_timedwait below */
580 if (ret == 0 && mutex_is_valid) {
581 /* and now we have the mutex again */
582 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
583 pthread_mutex_t*,mutex);
584 }
585
586 if (ret == 0 && mutex_is_valid) {
587 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
588 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
589 }
590
591 if (ret != 0) {
592 DO_PthAPIerror( "pthread_cond_wait", ret );
593 }
594
595 if (TRACE_PTH_FNS) {
596 fprintf(stderr, " cowait -> %d >>\n", ret);
597 }
598
599 return ret;
600}
601
602
603// pthread_cond_timedwait
604PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
605 pthread_cond_t* cond, pthread_mutex_t* mutex,
606 struct timespec* abstime)
607{
608 int ret;
609 OrigFn fn;
610 unsigned long mutex_is_valid;
611 VALGRIND_GET_ORIG_FN(fn);
612
613 if (TRACE_PTH_FNS) {
614 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
615 cond, mutex, abstime);
616 fflush(stderr);
617 }
618
619 /* Tell the tool a cond-wait is about to happen, so it can check
620 for bogus argument values. In return it tells us whether it
621 thinks the mutex is valid or not. */
622 DO_CREQ_W_WW(mutex_is_valid,
623 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
624 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
625 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
626
627 /* Tell the tool we're about to drop the mutex. This reflects the
628 fact that in a cond_wait, we show up holding the mutex, and the
629 call atomically drops the mutex and waits for the cv to be
630 signalled. */
631 if (mutex_is_valid) {
632 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
633 pthread_mutex_t*,mutex);
634 }
635
636 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
637
638 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
639 /* and now we have the mutex again */
640 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
641 pthread_mutex_t*,mutex);
642 }
643
644 if (ret == 0 && mutex_is_valid) {
645 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
646 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
647 }
648
649 if (ret != 0 && ret != ETIMEDOUT) {
650 DO_PthAPIerror( "pthread_cond_timedwait", ret );
651 }
652
653 if (TRACE_PTH_FNS) {
654 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
655 }
656
657 return ret;
658}
659
660
661// pthread_cond_signal
662PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
663 pthread_cond_t* cond)
664{
665 int ret;
666 OrigFn fn;
667 VALGRIND_GET_ORIG_FN(fn);
668
669 if (TRACE_PTH_FNS) {
670 fprintf(stderr, "<< pthread_cond_signal %p", cond);
671 fflush(stderr);
672 }
673
674 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
675 pthread_cond_t*,cond);
676
677 CALL_FN_W_W(ret, fn, cond);
678
679 if (ret != 0) {
680 DO_PthAPIerror( "pthread_cond_signal", ret );
681 }
682
683 if (TRACE_PTH_FNS) {
684 fprintf(stderr, " cosig -> %d >>\n", ret);
685 }
686
687 return ret;
688}
689
690
691// pthread_cond_broadcast
692// Note, this is pretty much identical, from a dependency-graph
693// point of view, with cond_signal, so the code is duplicated.
694// Maybe it should be commoned up.
695PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
696 pthread_cond_t* cond)
697{
698 int ret;
699 OrigFn fn;
700 VALGRIND_GET_ORIG_FN(fn);
701
702 if (TRACE_PTH_FNS) {
703 fprintf(stderr, "<< pthread_broadcast_signal %p", cond);
704 fflush(stderr);
705 }
706
707 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
708 pthread_cond_t*,cond);
709
710 CALL_FN_W_W(ret, fn, cond);
711
712 if (ret != 0) {
713 DO_PthAPIerror( "pthread_cond_broadcast", ret );
714 }
715
716 if (TRACE_PTH_FNS) {
717 fprintf(stderr, " cobro -> %d >>\n", ret);
718 }
719
720 return ret;
721}
722
723
sewardjf98e1c02008-10-25 16:22:41 +0000724// pthread_cond_destroy
725PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
726 pthread_cond_t* cond)
727{
728 int ret;
729 OrigFn fn;
730
731 VALGRIND_GET_ORIG_FN(fn);
732
733 if (TRACE_PTH_FNS) {
734 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
735 fflush(stderr);
736 }
737
738 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
739 pthread_cond_t*,cond);
740
741 CALL_FN_W_W(ret, fn, cond);
742
743 if (ret != 0) {
744 DO_PthAPIerror( "pthread_cond_destroy", ret );
745 }
746
747 if (TRACE_PTH_FNS) {
748 fprintf(stderr, " codestr -> %d >>\n", ret);
749 }
750
751 return ret;
752}
753
754
755/*----------------------------------------------------------------*/
756/*--- pthread_barrier_t functions ---*/
757/*----------------------------------------------------------------*/
758
sewardj9f569b72008-11-13 13:33:09 +0000759/* Handled: pthread_barrier_init
760 pthread_barrier_wait
761 pthread_barrier_destroy
762
763 Unhandled: pthread_barrierattr_destroy
764 pthread_barrierattr_getpshared
765 pthread_barrierattr_init
766 pthread_barrierattr_setpshared
767 -- are these important?
768*/
769
770PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
771 pthread_barrier_t* bar,
772 pthread_barrierattr_t* attr, unsigned long count)
sewardjf98e1c02008-10-25 16:22:41 +0000773{
774 int ret;
775 OrigFn fn;
776 VALGRIND_GET_ORIG_FN(fn);
777
778 if (TRACE_PTH_FNS) {
sewardj9f569b72008-11-13 13:33:09 +0000779 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
780 bar, attr, count);
sewardjf98e1c02008-10-25 16:22:41 +0000781 fflush(stderr);
782 }
783
sewardj9f569b72008-11-13 13:33:09 +0000784 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
785 pthread_barrier_t*,bar,
786 unsigned long,count);
sewardjf98e1c02008-10-25 16:22:41 +0000787
sewardj9f569b72008-11-13 13:33:09 +0000788 CALL_FN_W_WWW(ret, fn, bar,attr,count);
sewardjf98e1c02008-10-25 16:22:41 +0000789
sewardj9f569b72008-11-13 13:33:09 +0000790 if (ret != 0) {
791 DO_PthAPIerror( "pthread_barrier_init", ret );
792 }
793
794 if (TRACE_PTH_FNS) {
795 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
796 }
797
798 return ret;
799}
800
801
802PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
803 pthread_barrier_t* bar)
804{
805 int ret;
806 OrigFn fn;
807 VALGRIND_GET_ORIG_FN(fn);
808
809 if (TRACE_PTH_FNS) {
810 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
811 fflush(stderr);
812 }
813
814 /* That this works correctly, and doesn't screw up when a thread
815 leaving the barrier races round to the front and re-enters while
816 other threads are still leaving it, is quite subtle. See
817 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
818 hg_main.c. */
819 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
820 pthread_barrier_t*,bar);
821
822 CALL_FN_W_W(ret, fn, bar);
823
824 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
825 DO_PthAPIerror( "pthread_barrier_wait", ret );
826 }
sewardjf98e1c02008-10-25 16:22:41 +0000827
828 if (TRACE_PTH_FNS) {
829 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
830 }
831
832 return ret;
833}
834
835
sewardj9f569b72008-11-13 13:33:09 +0000836PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
837 pthread_barrier_t* bar)
838{
839 int ret;
840 OrigFn fn;
841 VALGRIND_GET_ORIG_FN(fn);
842
843 if (TRACE_PTH_FNS) {
844 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
845 fflush(stderr);
846 }
847
848 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
849 pthread_barrier_t*,bar);
850
851 CALL_FN_W_W(ret, fn, bar);
852
853 if (ret != 0) {
854 DO_PthAPIerror( "pthread_barrier_destroy", ret );
855 }
856
857 if (TRACE_PTH_FNS) {
858 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
859 }
860
861 return ret;
862}
sewardjf98e1c02008-10-25 16:22:41 +0000863
sewardjb4112022007-11-09 22:49:28 +0000864/*----------------------------------------------------------------*/
865/*--- pthread_rwlock_t functions ---*/
866/*----------------------------------------------------------------*/
867
868/* Handled: pthread_rwlock_init pthread_rwlock_destroy
869 pthread_rwlock_rdlock
870 pthread_rwlock_wrlock
871 pthread_rwlock_unlock
872
873 Unhandled: pthread_rwlock_timedrdlock
874 pthread_rwlock_tryrdlock
875
876 pthread_rwlock_timedwrlock
877 pthread_rwlock_trywrlock
878*/
879
880// pthread_rwlock_init
881PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
882 pthread_rwlock_t *rwl,
883 pthread_rwlockattr_t* attr)
884{
885 int ret;
886 OrigFn fn;
887 VALGRIND_GET_ORIG_FN(fn);
888 if (TRACE_PTH_FNS) {
889 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
890 }
891
892 CALL_FN_W_WW(ret, fn, rwl,attr);
893
894 if (ret == 0 /*success*/) {
895 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
896 pthread_rwlock_t*,rwl);
897 } else {
898 DO_PthAPIerror( "pthread_rwlock_init", ret );
899 }
900
901 if (TRACE_PTH_FNS) {
902 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
903 }
904 return ret;
905}
906
907
908// pthread_rwlock_destroy
909PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
910 pthread_rwlock_t *rwl)
911{
912 int ret;
913 OrigFn fn;
914 VALGRIND_GET_ORIG_FN(fn);
915 if (TRACE_PTH_FNS) {
916 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
917 }
918
919 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
920 pthread_rwlock_t*,rwl);
921
922 CALL_FN_W_W(ret, fn, rwl);
923
924 if (ret != 0) {
925 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
926 }
927
928 if (TRACE_PTH_FNS) {
929 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
930 }
931 return ret;
932}
933
934
sewardj789c3c52008-02-25 12:10:07 +0000935// pthread_rwlock_wrlock
sewardjb4112022007-11-09 22:49:28 +0000936PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
937 pthread_rwlock_t* rwlock)
938{
939 int ret;
940 OrigFn fn;
941 VALGRIND_GET_ORIG_FN(fn);
942 if (TRACE_PTH_FNS) {
943 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
944 }
945
sewardj789c3c52008-02-25 12:10:07 +0000946 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
947 pthread_rwlock_t*,rwlock,
948 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000949
950 CALL_FN_W_W(ret, fn, rwlock);
951
952 if (ret == 0 /*success*/) {
953 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
954 pthread_rwlock_t*,rwlock, long,1/*isW*/);
955 } else {
956 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
957 }
958
959 if (TRACE_PTH_FNS) {
960 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
961 }
962 return ret;
963}
964
965
sewardj789c3c52008-02-25 12:10:07 +0000966// pthread_rwlock_rdlock
sewardjb4112022007-11-09 22:49:28 +0000967PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
968 pthread_rwlock_t* rwlock)
969{
970 int ret;
971 OrigFn fn;
972 VALGRIND_GET_ORIG_FN(fn);
973 if (TRACE_PTH_FNS) {
974 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
975 }
976
sewardj789c3c52008-02-25 12:10:07 +0000977 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
978 pthread_rwlock_t*,rwlock,
979 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000980
981 CALL_FN_W_W(ret, fn, rwlock);
982
983 if (ret == 0 /*success*/) {
984 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
985 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
986 } else {
987 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
988 }
989
990 if (TRACE_PTH_FNS) {
991 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
992 }
993 return ret;
994}
995
996
sewardj789c3c52008-02-25 12:10:07 +0000997// pthread_rwlock_trywrlock
998PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
999 pthread_rwlock_t* rwlock)
1000{
1001 int ret;
1002 OrigFn fn;
1003 VALGRIND_GET_ORIG_FN(fn);
1004 if (TRACE_PTH_FNS) {
1005 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
1006 }
1007
1008 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1009 pthread_rwlock_t*,rwlock,
1010 long,1/*isW*/, long,1/*isTryLock*/);
1011
1012 CALL_FN_W_W(ret, fn, rwlock);
1013
1014 /* There's a hole here: libpthread now knows the lock is locked,
1015 but the tool doesn't, so some other thread could run and detect
1016 that the lock has been acquired by someone (this thread). Does
1017 this matter? Not sure, but I don't think so. */
1018
1019 if (ret == 0 /*success*/) {
1020 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1021 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1022 } else {
1023 if (ret != EBUSY)
1024 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
1025 }
1026
1027 if (TRACE_PTH_FNS) {
1028 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
1029 }
1030 return ret;
1031}
1032
1033
1034// pthread_rwlock_tryrdlock
1035PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
1036 pthread_rwlock_t* rwlock)
1037{
1038 int ret;
1039 OrigFn fn;
1040 VALGRIND_GET_ORIG_FN(fn);
1041 if (TRACE_PTH_FNS) {
1042 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
1043 }
1044
1045 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1046 pthread_rwlock_t*,rwlock,
1047 long,0/*!isW*/, long,1/*isTryLock*/);
1048
1049 CALL_FN_W_W(ret, fn, rwlock);
1050
1051 /* There's a hole here: libpthread now knows the lock is locked,
1052 but the tool doesn't, so some other thread could run and detect
1053 that the lock has been acquired by someone (this thread). Does
1054 this matter? Not sure, but I don't think so. */
1055
1056 if (ret == 0 /*success*/) {
1057 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1058 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1059 } else {
1060 if (ret != EBUSY)
1061 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
1062 }
1063
1064 if (TRACE_PTH_FNS) {
1065 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
1066 }
1067 return ret;
1068}
1069
1070
1071// pthread_rwlock_unlock
sewardjb4112022007-11-09 22:49:28 +00001072PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
1073 pthread_rwlock_t* rwlock)
1074{
1075 int ret;
1076 OrigFn fn;
1077 VALGRIND_GET_ORIG_FN(fn);
1078 if (TRACE_PTH_FNS) {
1079 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
1080 }
1081
1082 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1083 pthread_rwlock_t*,rwlock);
1084
1085 CALL_FN_W_W(ret, fn, rwlock);
1086
1087 if (ret == 0 /*success*/) {
1088 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1089 pthread_rwlock_t*,rwlock);
1090 } else {
1091 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
1092 }
1093
1094 if (TRACE_PTH_FNS) {
1095 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
1096 }
1097 return ret;
1098}
1099
1100
1101/*----------------------------------------------------------------*/
1102/*--- POSIX semaphores ---*/
1103/*----------------------------------------------------------------*/
1104
1105#include <semaphore.h>
1106
1107#define TRACE_SEM_FNS 0
1108
1109/* Handled:
1110 int sem_init(sem_t *sem, int pshared, unsigned value);
1111 int sem_destroy(sem_t *sem);
1112 int sem_wait(sem_t *sem);
1113 int sem_post(sem_t *sem);
1114
1115 Unhandled:
1116 int sem_trywait(sem_t *sem);
1117 int sem_timedwait(sem_t *restrict sem,
1118 const struct timespec *restrict abs_timeout);
1119*/
1120
1121/* glibc-2.5 has sem_init@@GLIBC_2.2.5 (amd64-linux)
1122 and sem_init@@GLIBC_2.1 (x86-linux): match sem_init@* */
1123PTH_FUNC(int, semZuinitZAZa, sem_t* sem, int pshared, unsigned long value)
1124{
1125 OrigFn fn;
1126 int ret;
1127 VALGRIND_GET_ORIG_FN(fn);
1128
1129 if (TRACE_SEM_FNS) {
1130 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
1131 fflush(stderr);
1132 }
1133
1134 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
1135
1136 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001137 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1138 sem_t*, sem, unsigned long, value);
sewardjb4112022007-11-09 22:49:28 +00001139 } else {
1140 DO_PthAPIerror( "sem_init", errno );
1141 }
1142
1143 if (TRACE_SEM_FNS) {
1144 fprintf(stderr, " sem_init -> %d >>\n", ret);
1145 fflush(stderr);
1146 }
1147
1148 return ret;
1149}
1150
1151
1152/* glibc-2.5 has sem_destroy@@GLIBC_2.2.5 (amd64-linux)
1153 and sem_destroy@@GLIBC_2.1 (x86-linux); match sem_destroy@* */
1154PTH_FUNC(int, semZudestroyZAZa, sem_t* sem)
1155{
1156 OrigFn fn;
1157 int ret;
1158 VALGRIND_GET_ORIG_FN(fn);
1159
1160 if (TRACE_SEM_FNS) {
1161 fprintf(stderr, "<< sem_destroy(%p) ", sem);
1162 fflush(stderr);
1163 }
1164
sewardj11e352f2007-11-30 11:11:02 +00001165 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
sewardjb4112022007-11-09 22:49:28 +00001166
1167 CALL_FN_W_W(ret, fn, sem);
1168
1169 if (ret != 0) {
1170 DO_PthAPIerror( "sem_destroy", errno );
1171 }
1172
1173 if (TRACE_SEM_FNS) {
1174 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
1175 fflush(stderr);
1176 }
1177
1178 return ret;
1179}
1180
1181
1182/* glibc-2.5 has sem_wait (amd64-linux); match sem_wait
1183 and sem_wait@@GLIBC_2.1 (x86-linux); match sem_wait@* */
1184/* wait: decrement semaphore - acquire lockage */
1185static int sem_wait_WRK(sem_t* sem)
1186{
1187 OrigFn fn;
1188 int ret;
1189 VALGRIND_GET_ORIG_FN(fn);
1190
1191 if (TRACE_SEM_FNS) {
1192 fprintf(stderr, "<< sem_wait(%p) ", sem);
1193 fflush(stderr);
1194 }
1195
1196 CALL_FN_W_W(ret, fn, sem);
1197
1198 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001199 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001200 } else {
1201 DO_PthAPIerror( "sem_wait", errno );
1202 }
1203
1204 if (TRACE_SEM_FNS) {
1205 fprintf(stderr, " sem_wait -> %d >>\n", ret);
1206 fflush(stderr);
1207 }
1208
1209 return ret;
1210}
1211PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1212 return sem_wait_WRK(sem);
1213}
1214PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
1215 return sem_wait_WRK(sem);
1216}
1217
1218
1219/* glibc-2.5 has sem_post (amd64-linux); match sem_post
1220 and sem_post@@GLIBC_2.1 (x86-linux); match sem_post@* */
1221/* post: increment semaphore - release lockage */
1222static int sem_post_WRK(sem_t* sem)
1223{
1224 OrigFn fn;
1225 int ret;
1226
1227 VALGRIND_GET_ORIG_FN(fn);
1228
1229 if (TRACE_SEM_FNS) {
1230 fprintf(stderr, "<< sem_post(%p) ", sem);
1231 fflush(stderr);
1232 }
1233
sewardj11e352f2007-11-30 11:11:02 +00001234 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001235
1236 CALL_FN_W_W(ret, fn, sem);
1237
1238 if (ret != 0) {
1239 DO_PthAPIerror( "sem_post", errno );
1240 }
1241
1242 if (TRACE_SEM_FNS) {
1243 fprintf(stderr, " sem_post -> %d >>\n", ret);
1244 fflush(stderr);
1245 }
1246
1247 return ret;
1248}
1249PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1250 return sem_post_WRK(sem);
1251}
1252PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1253 return sem_post_WRK(sem);
1254}
1255
1256
1257
1258/*----------------------------------------------------------------*/
1259/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
1260/*----------------------------------------------------------------*/
1261
sewardj38e0cf92008-11-19 10:40:56 +00001262/* Handled:
1263 QMutex::lock()
1264 QMutex::unlock()
1265 QMutex::tryLock()
1266 QMutex::tryLock(int)
sewardjb4112022007-11-09 22:49:28 +00001267
sewardj38e0cf92008-11-19 10:40:56 +00001268 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
1269 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
1270 QMutex::~QMutex() _ZN6QMutexD1Ev
1271 QMutex::~QMutex() _ZN6QMutexD2Ev
sewardjb4112022007-11-09 22:49:28 +00001272
sewardj38e0cf92008-11-19 10:40:56 +00001273 Unhandled:
1274 QReadWriteLock::lockForRead()
1275 QReadWriteLock::lockForWrite()
1276 QReadWriteLock::unlock()
1277 QReadWriteLock::tryLockForRead(int)
1278 QReadWriteLock::tryLockForRead()
1279 QReadWriteLock::tryLockForWrite(int)
1280 QReadWriteLock::tryLockForWrite()
1281
1282 QWaitCondition::wait(QMutex*, unsigned long)
1283 QWaitCondition::wakeAll()
1284 QWaitCondition::wakeOne()
1285
1286 QSemaphore::*
1287*/
1288/* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
1289 at least on Unix:
1290
1291 It's apparently only necessary to intercept QMutex, since that is
1292 not implemented using pthread_mutex_t; instead Qt4 has its own
1293 implementation based on atomics (to check the non-contended case)
1294 and pthread_cond_wait (to wait in the contended case).
1295
1296 QReadWriteLock is built on top of QMutex, counters, and a wait
1297 queue. So we don't need to handle it specially once QMutex
1298 handling is correct -- presumably the dependencies through QMutex
1299 are sufficient to avoid any false race reports. On the other hand,
1300 it is an open question whether too many dependencies are observed
1301 -- in which case we may miss races (false negatives). I suspect
1302 this is likely to be the case, unfortunately.
1303
1304 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
1305 and QReadWriteLock. Same compositional-correctness justificiation
1306 and limitations as fro QReadWriteLock.
1307
1308 Ditto QSemaphore (from cursory examination).
1309
1310 Does it matter that only QMutex is handled directly? Open
1311 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
1312 appears that no false errors are reported; however it is not clear
1313 if this is causing false negatives.
1314
1315 Another problem with Qt4 is thread exiting. Threads are created
1316 with pthread_create (fine); but they detach and simply exit when
1317 done. There is no use of pthread_join, and the provided
1318 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
1319 relies on a system of mutexes and flags. I suspect this also
1320 causes too many dependencies to appear. Consequently H sometimes
1321 fails to detect races at exit in some very short-lived racy
1322 programs, because it appears that a thread can exit _and_ have an
1323 observed dependency edge back to the main thread (presumably)
1324 before the main thread reaps the child (that is, calls
1325 QThread::wait).
1326
1327 This theory is supported by the observation that if all threads are
1328 made to wait at a pthread_barrier_t immediately before they exit,
1329 then H's detection of races in such programs becomes reliable;
1330 without the barrier, it is varies from run to run, depending
1331 (according to investigation) on whether aforementioned
1332 exit-before-reaping behaviour happens or not.
1333
1334 Finally, why is it necessary to intercept the QMutex constructors
1335 and destructors? The constructors are intercepted only as a matter
1336 of convenience, so H can print accurate "first observed at"
1337 clauses. However, it is actually necessary to intercept the
1338 destructors (as it is with pthread_mutex_destroy) in order that
1339 locks get removed from LAOG when they are destroyed.
sewardjb4112022007-11-09 22:49:28 +00001340*/
1341
1342// soname is libQtCore.so.4 ; match against libQtCore.so*
1343#define QT4_FUNC(ret_ty, f, args...) \
sewardj38e0cf92008-11-19 10:40:56 +00001344 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
1345 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
sewardjb4112022007-11-09 22:49:28 +00001346
1347// QMutex::lock()
sewardj38e0cf92008-11-19 10:40:56 +00001348QT4_FUNC(void, _ZN6QMutex4lockEv, void* self)
sewardjb4112022007-11-09 22:49:28 +00001349{
1350 OrigFn fn;
1351 VALGRIND_GET_ORIG_FN(fn);
1352 if (TRACE_QT4_FNS) {
1353 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
1354 }
1355
1356 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1357 void*,self, long,0/*!isTryLock*/);
1358
1359 CALL_FN_v_W(fn, self);
1360
1361 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1362 void*, self);
1363
1364 if (TRACE_QT4_FNS) {
1365 fprintf(stderr, " :: Q::lock done >>\n");
1366 }
1367}
1368
1369// QMutex::unlock()
sewardj38e0cf92008-11-19 10:40:56 +00001370QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self)
sewardjb4112022007-11-09 22:49:28 +00001371{
1372 OrigFn fn;
1373 VALGRIND_GET_ORIG_FN(fn);
1374
1375 if (TRACE_QT4_FNS) {
1376 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
1377 }
1378
1379 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1380 void*, self);
1381
1382 CALL_FN_v_W(fn, self);
1383
1384 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1385 void*, self);
1386
1387 if (TRACE_QT4_FNS) {
1388 fprintf(stderr, " Q::unlock done >>\n");
1389 }
1390}
1391
sewardj38e0cf92008-11-19 10:40:56 +00001392// bool QMutex::tryLock()
sewardjb4112022007-11-09 22:49:28 +00001393// using 'long' to mimic C++ 'bool'
sewardj38e0cf92008-11-19 10:40:56 +00001394QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self)
sewardjb4112022007-11-09 22:49:28 +00001395{
1396 OrigFn fn;
1397 long ret;
1398 VALGRIND_GET_ORIG_FN(fn);
1399 if (TRACE_QT4_FNS) {
1400 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
1401 }
1402
1403 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1404 void*,self, long,1/*isTryLock*/);
1405
1406 CALL_FN_W_W(ret, fn, self);
1407
1408 // assumes that only the low 8 bits of the 'bool' are significant
1409 if (ret & 0xFF) {
1410 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1411 void*, self);
1412 }
1413
1414 if (TRACE_QT4_FNS) {
1415 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
1416 }
1417
1418 return ret;
1419}
1420
sewardj38e0cf92008-11-19 10:40:56 +00001421// bool QMutex::tryLock(int)
1422// using 'long' to mimic C++ 'bool'
1423QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2)
sewardjb4112022007-11-09 22:49:28 +00001424{
1425 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00001426 long ret;
sewardjb4112022007-11-09 22:49:28 +00001427 VALGRIND_GET_ORIG_FN(fn);
1428 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00001429 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
sewardjb4112022007-11-09 22:49:28 +00001430 fflush(stderr);
1431 }
1432
sewardj38e0cf92008-11-19 10:40:56 +00001433 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1434 void*,self, long,1/*isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00001435
sewardj38e0cf92008-11-19 10:40:56 +00001436 CALL_FN_W_WW(ret, fn, self,arg2);
sewardjb4112022007-11-09 22:49:28 +00001437
sewardj38e0cf92008-11-19 10:40:56 +00001438 // assumes that only the low 8 bits of the 'bool' are significant
1439 if (ret & 0xFF) {
1440 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1441 void*, self);
1442 }
sewardjb4112022007-11-09 22:49:28 +00001443
1444 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00001445 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
sewardjb4112022007-11-09 22:49:28 +00001446 }
sewardj38e0cf92008-11-19 10:40:56 +00001447
1448 return ret;
sewardjb4112022007-11-09 22:49:28 +00001449}
1450
sewardj38e0cf92008-11-19 10:40:56 +00001451
1452// It's not really very clear what the args are here. But from
1453// a bit of dataflow analysis of the generated machine code of
1454// the original function, it appears this takes two args, and
1455// returns nothing. Nevertheless preserve return value just in
1456// case. A bit of debug printing indicates that the first arg
1457// is that of the mutex and the second is either zero or one,
1458// probably being the recursion mode, therefore.
1459// QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
1460QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE,
1461 void* mutex,
1462 long recmode)
sewardjb4112022007-11-09 22:49:28 +00001463{
1464 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00001465 long ret;
sewardjb4112022007-11-09 22:49:28 +00001466 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00001467 CALL_FN_W_WW(ret, fn, mutex, recmode);
1468 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
1469 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
1470 void*,mutex, long,1/*mbRec*/);
1471 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00001472}
1473
sewardj38e0cf92008-11-19 10:40:56 +00001474// QMutex::~QMutex() ("D1Ev" variant)
1475QT4_FUNC(void*, _ZN6QMutexD1Ev, void* mutex)
sewardjb4112022007-11-09 22:49:28 +00001476{
1477 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00001478 long ret;
sewardjb4112022007-11-09 22:49:28 +00001479 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00001480 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
1481 void*,mutex);
1482 CALL_FN_W_W(ret, fn, mutex);
1483 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00001484}
1485
1486
sewardj38e0cf92008-11-19 10:40:56 +00001487// QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
1488QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
1489 void* mutex,
1490 long recmode)
1491{
1492 assert(0);
1493}
1494
1495// QMutex::~QMutex() ("D2Ev" variant)
1496QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
1497{
1498 assert(0);
1499}
1500
1501
1502// QReadWriteLock is not intercepted directly. See comments
1503// above.
1504
1505//// QReadWriteLock::lockForRead()
1506//// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
1507//QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
1508// // _ZN14QReadWriteLock11lockForReadEv
1509// void* self)
1510//{
1511// OrigFn fn;
1512// VALGRIND_GET_ORIG_FN(fn);
1513// if (TRACE_QT4_FNS) {
1514// fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
1515// fflush(stderr);
1516// }
1517//
1518// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1519// void*,self,
1520// long,0/*!isW*/, long,0/*!isTryLock*/);
1521//
1522// CALL_FN_v_W(fn, self);
1523//
1524// DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1525// void*,self, long,0/*!isW*/);
1526//
1527// if (TRACE_QT4_FNS) {
1528// fprintf(stderr, " :: Q::lockForRead :: done >>\n");
1529// }
1530//}
1531//
1532//// QReadWriteLock::lockForWrite()
1533//// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
1534//QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
1535// // _ZN14QReadWriteLock12lockForWriteEv
1536// void* self)
1537//{
1538// OrigFn fn;
1539// VALGRIND_GET_ORIG_FN(fn);
1540// if (TRACE_QT4_FNS) {
1541// fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
1542// fflush(stderr);
1543// }
1544//
1545// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1546// void*,self,
1547// long,1/*isW*/, long,0/*!isTryLock*/);
1548//
1549// CALL_FN_v_W(fn, self);
1550//
1551// DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1552// void*,self, long,1/*isW*/);
1553//
1554// if (TRACE_QT4_FNS) {
1555// fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
1556// }
1557//}
1558//
1559//// QReadWriteLock::unlock()
1560//// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
1561//QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
1562// // _ZN14QReadWriteLock6unlockEv
1563// void* self)
1564//{
1565// OrigFn fn;
1566// VALGRIND_GET_ORIG_FN(fn);
1567// if (TRACE_QT4_FNS) {
1568// fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
1569// fflush(stderr);
1570// }
1571//
1572// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1573// void*,self);
1574//
1575// CALL_FN_v_W(fn, self);
1576//
1577// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1578// void*,self);
1579//
1580// if (TRACE_QT4_FNS) {
1581// fprintf(stderr, " :: Q::unlock :: done >>\n");
1582// }
1583//}
1584
1585
1586/*----------------------------------------------------------------*/
1587/*--- Replacements for basic string functions, that don't ---*/
1588/*--- the input arrays. ---*/
1589/*----------------------------------------------------------------*/
1590
1591/* Copied verbatim from memcheck/mc_replace_strmem.c. When copying
1592 new functions, please keep them in the same order as they appear in
1593 mc_replace_strmem.c. */
1594
1595/* --------- Some handy Z-encoded names. --------- */
1596
1597/* --- Soname of the standard C library. --- */
1598
1599#if defined(VGO_linux)
1600# define m_libc_soname libcZdsoZa // libc.so*
1601#elif defined(VGP_ppc32_aix5)
1602 /* AIX has both /usr/lib/libc.a and /usr/lib/libc_r.a. */
1603# define m_libc_soname libcZaZdaZLshrZdoZR // libc*.a(shr.o)
1604#elif defined(VGP_ppc64_aix5)
1605# define m_libc_soname libcZaZdaZLshrZu64ZdoZR // libc*.a(shr_64.o)
1606#else
1607# error "Unknown platform"
1608#endif
1609
1610/* --- Sonames for Linux ELF linkers. --- */
1611
1612#define m_ld_linux_so_2 ldZhlinuxZdsoZd2 // ld-linux.so.2
1613#define m_ld_linux_x86_64_so_2 ldZhlinuxZhx86Zh64ZdsoZd2 // ld-linux-x86-64.so.2
1614#define m_ld64_so_1 ld64ZdsoZd1 // ld64.so.1
1615#define m_ld_so_1 ldZdsoZd1 // ld.so.1
1616
1617
1618#define STRCHR(soname, fnname) \
1619 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \
1620 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \
1621 { \
1622 UChar ch = (UChar)((UInt)c); \
1623 UChar* p = (UChar*)s; \
1624 while (True) { \
1625 if (*p == ch) return p; \
1626 if (*p == 0) return NULL; \
1627 p++; \
1628 } \
1629 }
1630
1631// Apparently index() is the same thing as strchr()
1632STRCHR(m_libc_soname, strchr)
1633STRCHR(m_ld_linux_so_2, strchr)
1634STRCHR(m_ld_linux_x86_64_so_2, strchr)
1635STRCHR(m_libc_soname, index)
1636STRCHR(m_ld_linux_so_2, index)
1637STRCHR(m_ld_linux_x86_64_so_2, index)
1638
1639
1640// Note that this replacement often doesn't get used because gcc inlines
1641// calls to strlen() with its own built-in version. This can be very
1642// confusing if you aren't expecting it. Other small functions in this file
1643// may also be inline by gcc.
1644#define STRLEN(soname, fnname) \
1645 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
1646 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
1647 { \
1648 SizeT i = 0; \
1649 while (str[i] != 0) i++; \
1650 return i; \
1651 }
1652
1653STRLEN(m_libc_soname, strlen)
1654STRLEN(m_ld_linux_so_2, strlen)
1655STRLEN(m_ld_linux_x86_64_so_2, strlen)
1656
1657
1658#define STRCPY(soname, fnname) \
1659 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ); \
1660 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ) \
1661 { \
1662 const Char* dst_orig = dst; \
1663 \
1664 while (*src) *dst++ = *src++; \
1665 *dst = 0; \
1666 \
1667 return (char*)dst_orig; \
1668 }
1669
1670STRCPY(m_libc_soname, strcpy)
1671
1672
1673#define STRCMP(soname, fnname) \
1674 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1675 ( const char* s1, const char* s2 ); \
1676 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1677 ( const char* s1, const char* s2 ) \
1678 { \
1679 register unsigned char c1; \
1680 register unsigned char c2; \
1681 while (True) { \
1682 c1 = *(unsigned char *)s1; \
1683 c2 = *(unsigned char *)s2; \
1684 if (c1 != c2) break; \
1685 if (c1 == 0) break; \
1686 s1++; s2++; \
1687 } \
1688 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
1689 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
1690 return 0; \
1691 }
1692
1693STRCMP(m_libc_soname, strcmp)
1694STRCMP(m_ld_linux_x86_64_so_2, strcmp)
1695STRCMP(m_ld64_so_1, strcmp)
1696
1697
1698#define MEMCPY(soname, fnname) \
1699 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1700 ( void *dst, const void *src, SizeT len ); \
1701 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1702 ( void *dst, const void *src, SizeT len ) \
1703 { \
1704 register char *d; \
1705 register char *s; \
1706 \
1707 if (len == 0) \
1708 return dst; \
1709 \
1710 if ( dst > src ) { \
1711 d = (char *)dst + len - 1; \
1712 s = (char *)src + len - 1; \
1713 while ( len >= 4 ) { \
1714 *d-- = *s--; \
1715 *d-- = *s--; \
1716 *d-- = *s--; \
1717 *d-- = *s--; \
1718 len -= 4; \
1719 } \
1720 while ( len-- ) { \
1721 *d-- = *s--; \
1722 } \
1723 } else if ( dst < src ) { \
1724 d = (char *)dst; \
1725 s = (char *)src; \
1726 while ( len >= 4 ) { \
1727 *d++ = *s++; \
1728 *d++ = *s++; \
1729 *d++ = *s++; \
1730 *d++ = *s++; \
1731 len -= 4; \
1732 } \
1733 while ( len-- ) { \
1734 *d++ = *s++; \
1735 } \
1736 } \
1737 return dst; \
1738 }
1739
1740MEMCPY(m_libc_soname, memcpy)
1741MEMCPY(m_ld_so_1, memcpy) /* ld.so.1 */
1742MEMCPY(m_ld64_so_1, memcpy) /* ld64.so.1 */
1743/* icc9 blats these around all over the place. Not only in the main
1744 executable but various .so's. They are highly tuned and read
1745 memory beyond the source boundary (although work correctly and
1746 never go across page boundaries), so give errors when run natively,
1747 at least for misaligned source arg. Just intercepting in the exe
1748 only until we understand more about the problem. See
1749 http://bugs.kde.org/show_bug.cgi?id=139776
1750 */
1751MEMCPY(NONE, _intel_fast_memcpy)
1752
1753
sewardjb4112022007-11-09 22:49:28 +00001754/*--------------------------------------------------------------------*/
1755/*--- end tc_intercepts.c ---*/
1756/*--------------------------------------------------------------------*/