blob: 47cb3af767f888cfb3d51496ad03d750ac03eceb [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
njn9f207462009-03-10 22:02:09 +000011 Copyright (C) 2007-2009 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...) \
njn5f5ef2a2009-05-11 08:01:09 +000062 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
63 ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
sewardjb4112022007-11-09 22:49:28 +000064
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
njnf76d27a2009-05-28 01:53:07 +0000198// glibc-2.8.90 has "pthread_create@@GLIBC_2.2.5".
199// Darwin has "pthread_create".
200//
201// DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
202// functions that currently have them.
203static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
204 void *(*start) (void *), void *arg)
sewardjb4112022007-11-09 22:49:28 +0000205{
206 int ret;
207 OrigFn fn;
208 volatile Word xargs[3];
209
210 VALGRIND_GET_ORIG_FN(fn);
211 if (TRACE_PTH_FNS) {
212 fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr);
213 }
214 xargs[0] = (Word)start;
215 xargs[1] = (Word)arg;
216 xargs[2] = 1; /* serves as a spinlock -- sigh */
217
218 CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
219
220 if (ret == 0) {
221 /* we have to wait for the child to notify the tool of its
222 pthread_t before continuing */
223 while (xargs[2] != 0) {
sewardjeafad3b2007-11-18 01:16:52 +0000224 /* Do nothing. We need to spin until the child writes to
225 xargs[2]. However, that can lead to starvation in the
226 child and very long delays (eg, tc19_shadowmem on
227 ppc64-linux Fedora Core 6). So yield the cpu if we can,
228 to let the child run at the earliest available
229 opportunity. */
230 sched_yield();
sewardjb4112022007-11-09 22:49:28 +0000231 }
232 } else {
233 DO_PthAPIerror( "pthread_create", ret );
234 }
235
236 if (TRACE_PTH_FNS) {
237 fprintf(stderr, " :: pth_create -> %d >>\n", ret);
238 }
239 return ret;
240}
njnf76d27a2009-05-28 01:53:07 +0000241PTH_FUNC(int, pthreadZucreate, // pthread_create
242 pthread_t *thread, const pthread_attr_t *attr,
243 void *(*start) (void *), void *arg) {
244 return pthread_create_WRK(thread, attr, start, arg);
245}
246PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
247 pthread_t *thread, const pthread_attr_t *attr,
248 void *(*start) (void *), void *arg) {
249 return pthread_create_WRK(thread, attr, start, arg);
250}
sewardjb4112022007-11-09 22:49:28 +0000251
252// pthread_join
253PTH_FUNC(int, pthreadZujoin, // pthread_join
254 pthread_t thread, void** value_pointer)
255{
256 int ret;
257 OrigFn fn;
258 VALGRIND_GET_ORIG_FN(fn);
259 if (TRACE_PTH_FNS) {
260 fprintf(stderr, "<< pthread_join wrapper"); fflush(stderr);
261 }
262
263 CALL_FN_W_WW(ret, fn, thread,value_pointer);
264
265 /* At least with NPTL as the thread library, this is safe because
266 it is guaranteed (by NPTL) that the joiner will completely gone
267 before pthread_join (the original) returns. See email below.*/
268 if (ret == 0 /*success*/) {
269 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
270 } else {
271 DO_PthAPIerror( "pthread_join", ret );
272 }
273
274 if (TRACE_PTH_FNS) {
275 fprintf(stderr, " :: pth_join -> %d >>\n", ret);
276 }
277 return ret;
278}
279
280/* Behaviour of pthread_join on NPTL:
281
282Me:
283I have a question re the NPTL pthread_join implementation.
284
285 Suppose I am the thread 'stayer'.
286
287 If I call pthread_join(quitter), is it guaranteed that the
288 thread 'quitter' has really exited before pthread_join returns?
289
290 IOW, is it guaranteed that 'quitter' will not execute any further
291 instructions after pthread_join returns?
292
293I believe this is true based on the following analysis of
294glibc-2.5 sources. However am not 100% sure and would appreciate
295confirmation.
296
297 'quitter' will be running start_thread() in nptl/pthread_create.c
298
299 The last action of start_thread() is to exit via
300 __exit_thread_inline(0), which simply does sys_exit
301 (nptl/pthread_create.c:403)
302
303 'stayer' meanwhile is waiting for lll_wait_tid (pd->tid)
304 (call at nptl/pthread_join.c:89)
305
306 As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
307 lll_wait_tid will not return until kernel notifies via futex
308 wakeup that 'quitter' has terminated.
309
310 Hence pthread_join cannot return until 'quitter' really has
311 completely disappeared.
312
313Drepper:
314> As per comment at nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h:536,
315> lll_wait_tid will not return until kernel notifies via futex
316> wakeup that 'quitter' has terminated.
317That's the key. The kernel resets the TID field after the thread is
318done. No way the joiner can return before the thread is gone.
319*/
320
321
322/*----------------------------------------------------------------*/
323/*--- pthread_mutex_t functions ---*/
324/*----------------------------------------------------------------*/
325
326/* Handled: pthread_mutex_init pthread_mutex_destroy
327 pthread_mutex_lock
328 pthread_mutex_trylock pthread_mutex_timedlock
329 pthread_mutex_unlock
330
331 Unhandled: pthread_spin_init pthread_spin_destroy
332 pthread_spin_lock
333 pthread_spin_trylock
334 pthread_spin_unlock
335*/
336
337// pthread_mutex_init
338PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
339 pthread_mutex_t *mutex,
340 pthread_mutexattr_t* attr)
341{
342 int ret;
343 long mbRec;
344 OrigFn fn;
345 VALGRIND_GET_ORIG_FN(fn);
346 if (TRACE_PTH_FNS) {
347 fprintf(stderr, "<< pthread_mxinit %p", mutex); fflush(stderr);
348 }
349
350 mbRec = 0;
351 if (attr) {
352 int ty, zzz;
353 zzz = pthread_mutexattr_gettype(attr, &ty);
354 if (zzz == 0 && ty == PTHREAD_MUTEX_RECURSIVE)
355 mbRec = 1;
356 }
357
358 CALL_FN_W_WW(ret, fn, mutex,attr);
359
360 if (ret == 0 /*success*/) {
361 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
362 pthread_mutex_t*,mutex, long,mbRec);
363 } else {
364 DO_PthAPIerror( "pthread_mutex_init", ret );
365 }
366
367 if (TRACE_PTH_FNS) {
368 fprintf(stderr, " :: mxinit -> %d >>\n", ret);
369 }
370 return ret;
371}
372
373
374// pthread_mutex_destroy
375PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
376 pthread_mutex_t *mutex)
377{
378 int ret;
379 OrigFn fn;
380 VALGRIND_GET_ORIG_FN(fn);
381 if (TRACE_PTH_FNS) {
382 fprintf(stderr, "<< pthread_mxdestroy %p", mutex); fflush(stderr);
383 }
384
385 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
386 pthread_mutex_t*,mutex);
387
388 CALL_FN_W_W(ret, fn, mutex);
389
390 if (ret != 0) {
391 DO_PthAPIerror( "pthread_mutex_destroy", ret );
392 }
393
394 if (TRACE_PTH_FNS) {
395 fprintf(stderr, " :: mxdestroy -> %d >>\n", ret);
396 }
397 return ret;
398}
399
400
401// pthread_mutex_lock
402PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
403 pthread_mutex_t *mutex)
404{
405 int ret;
406 OrigFn fn;
407 VALGRIND_GET_ORIG_FN(fn);
408 if (TRACE_PTH_FNS) {
409 fprintf(stderr, "<< pthread_mxlock %p", mutex); fflush(stderr);
410 }
411
412 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
413 pthread_mutex_t*,mutex, long,0/*!isTryLock*/);
414
415 CALL_FN_W_W(ret, fn, mutex);
416
417 /* There's a hole here: libpthread now knows the lock is locked,
418 but the tool doesn't, so some other thread could run and detect
419 that the lock has been acquired by someone (this thread). Does
420 this matter? Not sure, but I don't think so. */
421
422 if (ret == 0 /*success*/) {
423 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
424 pthread_mutex_t*,mutex);
425 } else {
426 DO_PthAPIerror( "pthread_mutex_lock", ret );
427 }
428
429 if (TRACE_PTH_FNS) {
430 fprintf(stderr, " :: mxlock -> %d >>\n", ret);
431 }
432 return ret;
433}
434
435
436// pthread_mutex_trylock. The handling needed here is very similar
437// to that for pthread_mutex_lock, except that we need to tell
438// the pre-lock creq that this is a trylock-style operation, and
439// therefore not to complain if the lock is nonrecursive and
440// already locked by this thread -- because then it'll just fail
441// immediately with EBUSY.
442PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
443 pthread_mutex_t *mutex)
444{
445 int ret;
446 OrigFn fn;
447 VALGRIND_GET_ORIG_FN(fn);
448 if (TRACE_PTH_FNS) {
449 fprintf(stderr, "<< pthread_mxtrylock %p", mutex); fflush(stderr);
450 }
451
452 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
453 pthread_mutex_t*,mutex, long,1/*isTryLock*/);
454
455 CALL_FN_W_W(ret, fn, mutex);
456
457 /* There's a hole here: libpthread now knows the lock is locked,
458 but the tool doesn't, so some other thread could run and detect
459 that the lock has been acquired by someone (this thread). Does
460 this matter? Not sure, but I don't think so. */
461
462 if (ret == 0 /*success*/) {
463 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
464 pthread_mutex_t*,mutex);
465 } else {
466 if (ret != EBUSY)
467 DO_PthAPIerror( "pthread_mutex_trylock", ret );
468 }
469
470 if (TRACE_PTH_FNS) {
471 fprintf(stderr, " :: mxtrylock -> %d >>\n", ret);
472 }
473 return ret;
474}
475
476
477// pthread_mutex_timedlock. Identical logic to pthread_mutex_trylock.
478PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
479 pthread_mutex_t *mutex,
480 void* timeout)
481{
482 int ret;
483 OrigFn fn;
484 VALGRIND_GET_ORIG_FN(fn);
485 if (TRACE_PTH_FNS) {
486 fprintf(stderr, "<< pthread_mxtimedlock %p %p", mutex, timeout);
487 fflush(stderr);
488 }
489
490 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
491 pthread_mutex_t*,mutex, long,1/*isTryLock-ish*/);
492
493 CALL_FN_W_WW(ret, fn, mutex,timeout);
494
495 /* There's a hole here: libpthread now knows the lock is locked,
496 but the tool doesn't, so some other thread could run and detect
497 that the lock has been acquired by someone (this thread). Does
498 this matter? Not sure, but I don't think so. */
499
500 if (ret == 0 /*success*/) {
501 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
502 pthread_mutex_t*,mutex);
503 } else {
504 if (ret != ETIMEDOUT)
505 DO_PthAPIerror( "pthread_mutex_timedlock", ret );
506 }
507
508 if (TRACE_PTH_FNS) {
509 fprintf(stderr, " :: mxtimedlock -> %d >>\n", ret);
510 }
511 return ret;
512}
513
514
515// pthread_mutex_unlock
516PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
517 pthread_mutex_t *mutex)
518{
519 int ret;
520 OrigFn fn;
521 VALGRIND_GET_ORIG_FN(fn);
522
523 if (TRACE_PTH_FNS) {
524 fprintf(stderr, "<< pthread_mxunlk %p", mutex); fflush(stderr);
525 }
526
527 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
528 pthread_mutex_t*,mutex);
529
530 CALL_FN_W_W(ret, fn, mutex);
531
532 if (ret == 0 /*success*/) {
533 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
534 pthread_mutex_t*,mutex);
535 } else {
536 DO_PthAPIerror( "pthread_mutex_unlock", ret );
537 }
538
539 if (TRACE_PTH_FNS) {
540 fprintf(stderr, " mxunlk -> %d >>\n", ret);
541 }
542 return ret;
543}
544
545
546/*----------------------------------------------------------------*/
547/*--- pthread_cond_t functions ---*/
548/*----------------------------------------------------------------*/
549
550/* Handled: pthread_cond_wait pthread_cond_timedwait
551 pthread_cond_signal pthread_cond_broadcast
sewardjf98e1c02008-10-25 16:22:41 +0000552 pthread_cond_destroy
sewardjb4112022007-11-09 22:49:28 +0000553
sewardjf98e1c02008-10-25 16:22:41 +0000554 Unhandled: pthread_cond_init
555 -- is this important?
sewardjb4112022007-11-09 22:49:28 +0000556*/
557
558// pthread_cond_wait
559PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
560 pthread_cond_t* cond, pthread_mutex_t* mutex)
561{
562 int ret;
563 OrigFn fn;
564 unsigned long mutex_is_valid;
565
566 VALGRIND_GET_ORIG_FN(fn);
567
568 if (TRACE_PTH_FNS) {
569 fprintf(stderr, "<< pthread_cond_wait %p %p", cond, mutex);
570 fflush(stderr);
571 }
572
573 /* Tell the tool a cond-wait is about to happen, so it can check
574 for bogus argument values. In return it tells us whether it
575 thinks the mutex is valid or not. */
576 DO_CREQ_W_WW(mutex_is_valid,
577 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
578 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
579 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
580
581 /* Tell the tool we're about to drop the mutex. This reflects the
582 fact that in a cond_wait, we show up holding the mutex, and the
583 call atomically drops the mutex and waits for the cv to be
584 signalled. */
585 if (mutex_is_valid) {
586 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
587 pthread_mutex_t*,mutex);
588 }
589
590 CALL_FN_W_WW(ret, fn, cond,mutex);
591
592 /* these conditionals look stupid, but compare w/ same logic for
593 pthread_cond_timedwait below */
594 if (ret == 0 && mutex_is_valid) {
595 /* and now we have the mutex again */
596 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
597 pthread_mutex_t*,mutex);
598 }
599
600 if (ret == 0 && mutex_is_valid) {
601 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
602 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
603 }
604
605 if (ret != 0) {
606 DO_PthAPIerror( "pthread_cond_wait", ret );
607 }
608
609 if (TRACE_PTH_FNS) {
610 fprintf(stderr, " cowait -> %d >>\n", ret);
611 }
612
613 return ret;
614}
615
616
617// pthread_cond_timedwait
618PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
619 pthread_cond_t* cond, pthread_mutex_t* mutex,
620 struct timespec* abstime)
621{
622 int ret;
623 OrigFn fn;
624 unsigned long mutex_is_valid;
625 VALGRIND_GET_ORIG_FN(fn);
626
627 if (TRACE_PTH_FNS) {
628 fprintf(stderr, "<< pthread_cond_timedwait %p %p %p",
629 cond, mutex, abstime);
630 fflush(stderr);
631 }
632
633 /* Tell the tool a cond-wait is about to happen, so it can check
634 for bogus argument values. In return it tells us whether it
635 thinks the mutex is valid or not. */
636 DO_CREQ_W_WW(mutex_is_valid,
637 _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
638 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
639 assert(mutex_is_valid == 1 || mutex_is_valid == 0);
640
641 /* Tell the tool we're about to drop the mutex. This reflects the
642 fact that in a cond_wait, we show up holding the mutex, and the
643 call atomically drops the mutex and waits for the cv to be
644 signalled. */
645 if (mutex_is_valid) {
646 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
647 pthread_mutex_t*,mutex);
648 }
649
650 CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
651
652 if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
653 /* and now we have the mutex again */
654 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
655 pthread_mutex_t*,mutex);
656 }
657
658 if (ret == 0 && mutex_is_valid) {
659 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
660 pthread_cond_t*,cond, pthread_mutex_t*,mutex);
661 }
662
663 if (ret != 0 && ret != ETIMEDOUT) {
664 DO_PthAPIerror( "pthread_cond_timedwait", ret );
665 }
666
667 if (TRACE_PTH_FNS) {
668 fprintf(stderr, " cotimedwait -> %d >>\n", ret);
669 }
670
671 return ret;
672}
673
674
675// pthread_cond_signal
676PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
677 pthread_cond_t* cond)
678{
679 int ret;
680 OrigFn fn;
681 VALGRIND_GET_ORIG_FN(fn);
682
683 if (TRACE_PTH_FNS) {
684 fprintf(stderr, "<< pthread_cond_signal %p", cond);
685 fflush(stderr);
686 }
687
688 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,
689 pthread_cond_t*,cond);
690
691 CALL_FN_W_W(ret, fn, cond);
692
693 if (ret != 0) {
694 DO_PthAPIerror( "pthread_cond_signal", ret );
695 }
696
697 if (TRACE_PTH_FNS) {
698 fprintf(stderr, " cosig -> %d >>\n", ret);
699 }
700
701 return ret;
702}
703
704
705// pthread_cond_broadcast
706// Note, this is pretty much identical, from a dependency-graph
707// point of view, with cond_signal, so the code is duplicated.
708// Maybe it should be commoned up.
709PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
710 pthread_cond_t* cond)
711{
712 int ret;
713 OrigFn fn;
714 VALGRIND_GET_ORIG_FN(fn);
715
716 if (TRACE_PTH_FNS) {
717 fprintf(stderr, "<< pthread_broadcast_signal %p", cond);
718 fflush(stderr);
719 }
720
721 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE,
722 pthread_cond_t*,cond);
723
724 CALL_FN_W_W(ret, fn, cond);
725
726 if (ret != 0) {
727 DO_PthAPIerror( "pthread_cond_broadcast", ret );
728 }
729
730 if (TRACE_PTH_FNS) {
731 fprintf(stderr, " cobro -> %d >>\n", ret);
732 }
733
734 return ret;
735}
736
737
sewardjf98e1c02008-10-25 16:22:41 +0000738// pthread_cond_destroy
739PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
740 pthread_cond_t* cond)
741{
742 int ret;
743 OrigFn fn;
744
745 VALGRIND_GET_ORIG_FN(fn);
746
747 if (TRACE_PTH_FNS) {
748 fprintf(stderr, "<< pthread_cond_destroy %p", cond);
749 fflush(stderr);
750 }
751
752 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE,
753 pthread_cond_t*,cond);
754
755 CALL_FN_W_W(ret, fn, cond);
756
757 if (ret != 0) {
758 DO_PthAPIerror( "pthread_cond_destroy", ret );
759 }
760
761 if (TRACE_PTH_FNS) {
762 fprintf(stderr, " codestr -> %d >>\n", ret);
763 }
764
765 return ret;
766}
767
768
769/*----------------------------------------------------------------*/
770/*--- pthread_barrier_t functions ---*/
771/*----------------------------------------------------------------*/
772
njnf76d27a2009-05-28 01:53:07 +0000773#if defined(HAVE_PTHREAD_BARRIER_INIT)
774
sewardj9f569b72008-11-13 13:33:09 +0000775/* Handled: pthread_barrier_init
776 pthread_barrier_wait
777 pthread_barrier_destroy
778
779 Unhandled: pthread_barrierattr_destroy
780 pthread_barrierattr_getpshared
781 pthread_barrierattr_init
782 pthread_barrierattr_setpshared
783 -- are these important?
784*/
785
786PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
787 pthread_barrier_t* bar,
788 pthread_barrierattr_t* attr, unsigned long count)
sewardjf98e1c02008-10-25 16:22:41 +0000789{
790 int ret;
791 OrigFn fn;
792 VALGRIND_GET_ORIG_FN(fn);
793
794 if (TRACE_PTH_FNS) {
sewardj9f569b72008-11-13 13:33:09 +0000795 fprintf(stderr, "<< pthread_barrier_init %p %p %lu",
796 bar, attr, count);
sewardjf98e1c02008-10-25 16:22:41 +0000797 fflush(stderr);
798 }
799
sewardj9f569b72008-11-13 13:33:09 +0000800 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,
801 pthread_barrier_t*,bar,
802 unsigned long,count);
sewardjf98e1c02008-10-25 16:22:41 +0000803
sewardj9f569b72008-11-13 13:33:09 +0000804 CALL_FN_W_WWW(ret, fn, bar,attr,count);
sewardjf98e1c02008-10-25 16:22:41 +0000805
sewardj9f569b72008-11-13 13:33:09 +0000806 if (ret != 0) {
807 DO_PthAPIerror( "pthread_barrier_init", ret );
808 }
809
810 if (TRACE_PTH_FNS) {
811 fprintf(stderr, " pthread_barrier_init -> %d >>\n", ret);
812 }
813
814 return ret;
815}
816
817
818PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
819 pthread_barrier_t* bar)
820{
821 int ret;
822 OrigFn fn;
823 VALGRIND_GET_ORIG_FN(fn);
824
825 if (TRACE_PTH_FNS) {
826 fprintf(stderr, "<< pthread_barrier_wait %p", bar);
827 fflush(stderr);
828 }
829
830 /* That this works correctly, and doesn't screw up when a thread
831 leaving the barrier races round to the front and re-enters while
832 other threads are still leaving it, is quite subtle. See
833 comments in the handler for PTHREAD_BARRIER_WAIT_PRE in
834 hg_main.c. */
835 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,
836 pthread_barrier_t*,bar);
837
838 CALL_FN_W_W(ret, fn, bar);
839
840 if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) {
841 DO_PthAPIerror( "pthread_barrier_wait", ret );
842 }
sewardjf98e1c02008-10-25 16:22:41 +0000843
844 if (TRACE_PTH_FNS) {
845 fprintf(stderr, " pthread_barrier_wait -> %d >>\n", ret);
846 }
847
848 return ret;
849}
850
851
sewardj9f569b72008-11-13 13:33:09 +0000852PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
853 pthread_barrier_t* bar)
854{
855 int ret;
856 OrigFn fn;
857 VALGRIND_GET_ORIG_FN(fn);
858
859 if (TRACE_PTH_FNS) {
860 fprintf(stderr, "<< pthread_barrier_destroy %p", bar);
861 fflush(stderr);
862 }
863
864 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE,
865 pthread_barrier_t*,bar);
866
867 CALL_FN_W_W(ret, fn, bar);
868
869 if (ret != 0) {
870 DO_PthAPIerror( "pthread_barrier_destroy", ret );
871 }
872
873 if (TRACE_PTH_FNS) {
874 fprintf(stderr, " pthread_barrier_destroy -> %d >>\n", ret);
875 }
876
877 return ret;
878}
sewardjf98e1c02008-10-25 16:22:41 +0000879
njnf76d27a2009-05-28 01:53:07 +0000880#endif // defined(HAVE_PTHREAD_BARRIER_INIT)
881
sewardjb4112022007-11-09 22:49:28 +0000882/*----------------------------------------------------------------*/
883/*--- pthread_rwlock_t functions ---*/
884/*----------------------------------------------------------------*/
885
886/* Handled: pthread_rwlock_init pthread_rwlock_destroy
887 pthread_rwlock_rdlock
888 pthread_rwlock_wrlock
889 pthread_rwlock_unlock
890
891 Unhandled: pthread_rwlock_timedrdlock
892 pthread_rwlock_tryrdlock
893
894 pthread_rwlock_timedwrlock
895 pthread_rwlock_trywrlock
896*/
897
898// pthread_rwlock_init
899PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init
900 pthread_rwlock_t *rwl,
901 pthread_rwlockattr_t* attr)
902{
903 int ret;
904 OrigFn fn;
905 VALGRIND_GET_ORIG_FN(fn);
906 if (TRACE_PTH_FNS) {
907 fprintf(stderr, "<< pthread_rwl_init %p", rwl); fflush(stderr);
908 }
909
910 CALL_FN_W_WW(ret, fn, rwl,attr);
911
912 if (ret == 0 /*success*/) {
913 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
914 pthread_rwlock_t*,rwl);
915 } else {
916 DO_PthAPIerror( "pthread_rwlock_init", ret );
917 }
918
919 if (TRACE_PTH_FNS) {
920 fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
921 }
922 return ret;
923}
924
925
926// pthread_rwlock_destroy
927PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy
928 pthread_rwlock_t *rwl)
929{
930 int ret;
931 OrigFn fn;
932 VALGRIND_GET_ORIG_FN(fn);
933 if (TRACE_PTH_FNS) {
934 fprintf(stderr, "<< pthread_rwl_destroy %p", rwl); fflush(stderr);
935 }
936
937 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE,
938 pthread_rwlock_t*,rwl);
939
940 CALL_FN_W_W(ret, fn, rwl);
941
942 if (ret != 0) {
943 DO_PthAPIerror( "pthread_rwlock_destroy", ret );
944 }
945
946 if (TRACE_PTH_FNS) {
947 fprintf(stderr, " :: rwl_destroy -> %d >>\n", ret);
948 }
949 return ret;
950}
951
952
sewardj789c3c52008-02-25 12:10:07 +0000953// pthread_rwlock_wrlock
sewardjb4112022007-11-09 22:49:28 +0000954PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock
955 pthread_rwlock_t* rwlock)
956{
957 int ret;
958 OrigFn fn;
959 VALGRIND_GET_ORIG_FN(fn);
960 if (TRACE_PTH_FNS) {
961 fprintf(stderr, "<< pthread_rwl_wlk %p", rwlock); fflush(stderr);
962 }
963
sewardj789c3c52008-02-25 12:10:07 +0000964 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
965 pthread_rwlock_t*,rwlock,
966 long,1/*isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000967
968 CALL_FN_W_W(ret, fn, rwlock);
969
970 if (ret == 0 /*success*/) {
971 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
972 pthread_rwlock_t*,rwlock, long,1/*isW*/);
973 } else {
974 DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
975 }
976
977 if (TRACE_PTH_FNS) {
978 fprintf(stderr, " :: rwl_wlk -> %d >>\n", ret);
979 }
980 return ret;
981}
982
983
sewardj789c3c52008-02-25 12:10:07 +0000984// pthread_rwlock_rdlock
sewardjb4112022007-11-09 22:49:28 +0000985PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock
986 pthread_rwlock_t* rwlock)
987{
988 int ret;
989 OrigFn fn;
990 VALGRIND_GET_ORIG_FN(fn);
991 if (TRACE_PTH_FNS) {
992 fprintf(stderr, "<< pthread_rwl_rlk %p", rwlock); fflush(stderr);
993 }
994
sewardj789c3c52008-02-25 12:10:07 +0000995 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
996 pthread_rwlock_t*,rwlock,
997 long,0/*!isW*/, long,0/*!isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +0000998
999 CALL_FN_W_W(ret, fn, rwlock);
1000
1001 if (ret == 0 /*success*/) {
1002 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1003 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1004 } else {
1005 DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
1006 }
1007
1008 if (TRACE_PTH_FNS) {
1009 fprintf(stderr, " :: rwl_rlk -> %d >>\n", ret);
1010 }
1011 return ret;
1012}
1013
1014
sewardj789c3c52008-02-25 12:10:07 +00001015// pthread_rwlock_trywrlock
1016PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock
1017 pthread_rwlock_t* rwlock)
1018{
1019 int ret;
1020 OrigFn fn;
1021 VALGRIND_GET_ORIG_FN(fn);
1022 if (TRACE_PTH_FNS) {
1023 fprintf(stderr, "<< pthread_rwl_trywlk %p", rwlock); fflush(stderr);
1024 }
1025
1026 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1027 pthread_rwlock_t*,rwlock,
1028 long,1/*isW*/, long,1/*isTryLock*/);
1029
1030 CALL_FN_W_W(ret, fn, rwlock);
1031
1032 /* There's a hole here: libpthread now knows the lock is locked,
1033 but the tool doesn't, so some other thread could run and detect
1034 that the lock has been acquired by someone (this thread). Does
1035 this matter? Not sure, but I don't think so. */
1036
1037 if (ret == 0 /*success*/) {
1038 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1039 pthread_rwlock_t*,rwlock, long,1/*isW*/);
1040 } else {
1041 if (ret != EBUSY)
1042 DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
1043 }
1044
1045 if (TRACE_PTH_FNS) {
1046 fprintf(stderr, " :: rwl_trywlk -> %d >>\n", ret);
1047 }
1048 return ret;
1049}
1050
1051
1052// pthread_rwlock_tryrdlock
1053PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock
1054 pthread_rwlock_t* rwlock)
1055{
1056 int ret;
1057 OrigFn fn;
1058 VALGRIND_GET_ORIG_FN(fn);
1059 if (TRACE_PTH_FNS) {
1060 fprintf(stderr, "<< pthread_rwl_tryrlk %p", rwlock); fflush(stderr);
1061 }
1062
1063 DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1064 pthread_rwlock_t*,rwlock,
1065 long,0/*!isW*/, long,1/*isTryLock*/);
1066
1067 CALL_FN_W_W(ret, fn, rwlock);
1068
1069 /* There's a hole here: libpthread now knows the lock is locked,
1070 but the tool doesn't, so some other thread could run and detect
1071 that the lock has been acquired by someone (this thread). Does
1072 this matter? Not sure, but I don't think so. */
1073
1074 if (ret == 0 /*success*/) {
1075 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1076 pthread_rwlock_t*,rwlock, long,0/*!isW*/);
1077 } else {
1078 if (ret != EBUSY)
1079 DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
1080 }
1081
1082 if (TRACE_PTH_FNS) {
1083 fprintf(stderr, " :: rwl_tryrlk -> %d >>\n", ret);
1084 }
1085 return ret;
1086}
1087
1088
1089// pthread_rwlock_unlock
sewardjb4112022007-11-09 22:49:28 +00001090PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock
1091 pthread_rwlock_t* rwlock)
1092{
1093 int ret;
1094 OrigFn fn;
1095 VALGRIND_GET_ORIG_FN(fn);
1096 if (TRACE_PTH_FNS) {
1097 fprintf(stderr, "<< pthread_rwl_unlk %p", rwlock); fflush(stderr);
1098 }
1099
1100 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1101 pthread_rwlock_t*,rwlock);
1102
1103 CALL_FN_W_W(ret, fn, rwlock);
1104
1105 if (ret == 0 /*success*/) {
1106 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1107 pthread_rwlock_t*,rwlock);
1108 } else {
1109 DO_PthAPIerror( "pthread_rwlock_unlock", ret );
1110 }
1111
1112 if (TRACE_PTH_FNS) {
1113 fprintf(stderr, " :: rwl_unlk -> %d >>\n", ret);
1114 }
1115 return ret;
1116}
1117
1118
1119/*----------------------------------------------------------------*/
1120/*--- POSIX semaphores ---*/
1121/*----------------------------------------------------------------*/
1122
1123#include <semaphore.h>
1124
1125#define TRACE_SEM_FNS 0
1126
1127/* Handled:
1128 int sem_init(sem_t *sem, int pshared, unsigned value);
1129 int sem_destroy(sem_t *sem);
1130 int sem_wait(sem_t *sem);
1131 int sem_post(sem_t *sem);
1132
1133 Unhandled:
1134 int sem_trywait(sem_t *sem);
1135 int sem_timedwait(sem_t *restrict sem,
1136 const struct timespec *restrict abs_timeout);
1137*/
1138
1139/* glibc-2.5 has sem_init@@GLIBC_2.2.5 (amd64-linux)
1140 and sem_init@@GLIBC_2.1 (x86-linux): match sem_init@* */
1141PTH_FUNC(int, semZuinitZAZa, sem_t* sem, int pshared, unsigned long value)
1142{
1143 OrigFn fn;
1144 int ret;
1145 VALGRIND_GET_ORIG_FN(fn);
1146
1147 if (TRACE_SEM_FNS) {
1148 fprintf(stderr, "<< sem_init(%p,%d,%lu) ", sem,pshared,value);
1149 fflush(stderr);
1150 }
1151
1152 CALL_FN_W_WWW(ret, fn, sem,pshared,value);
1153
1154 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001155 DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
1156 sem_t*, sem, unsigned long, value);
sewardjb4112022007-11-09 22:49:28 +00001157 } else {
1158 DO_PthAPIerror( "sem_init", errno );
1159 }
1160
1161 if (TRACE_SEM_FNS) {
1162 fprintf(stderr, " sem_init -> %d >>\n", ret);
1163 fflush(stderr);
1164 }
1165
1166 return ret;
1167}
1168
1169
1170/* glibc-2.5 has sem_destroy@@GLIBC_2.2.5 (amd64-linux)
1171 and sem_destroy@@GLIBC_2.1 (x86-linux); match sem_destroy@* */
1172PTH_FUNC(int, semZudestroyZAZa, sem_t* sem)
1173{
1174 OrigFn fn;
1175 int ret;
1176 VALGRIND_GET_ORIG_FN(fn);
1177
1178 if (TRACE_SEM_FNS) {
1179 fprintf(stderr, "<< sem_destroy(%p) ", sem);
1180 fflush(stderr);
1181 }
1182
sewardj11e352f2007-11-30 11:11:02 +00001183 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, sem_t*, sem);
sewardjb4112022007-11-09 22:49:28 +00001184
1185 CALL_FN_W_W(ret, fn, sem);
1186
1187 if (ret != 0) {
1188 DO_PthAPIerror( "sem_destroy", errno );
1189 }
1190
1191 if (TRACE_SEM_FNS) {
1192 fprintf(stderr, " sem_destroy -> %d >>\n", ret);
1193 fflush(stderr);
1194 }
1195
1196 return ret;
1197}
1198
1199
1200/* glibc-2.5 has sem_wait (amd64-linux); match sem_wait
1201 and sem_wait@@GLIBC_2.1 (x86-linux); match sem_wait@* */
1202/* wait: decrement semaphore - acquire lockage */
1203static int sem_wait_WRK(sem_t* sem)
1204{
1205 OrigFn fn;
1206 int ret;
1207 VALGRIND_GET_ORIG_FN(fn);
1208
1209 if (TRACE_SEM_FNS) {
1210 fprintf(stderr, "<< sem_wait(%p) ", sem);
1211 fflush(stderr);
1212 }
1213
1214 CALL_FN_W_W(ret, fn, sem);
1215
1216 if (ret == 0) {
sewardj11e352f2007-11-30 11:11:02 +00001217 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001218 } else {
1219 DO_PthAPIerror( "sem_wait", errno );
1220 }
1221
1222 if (TRACE_SEM_FNS) {
1223 fprintf(stderr, " sem_wait -> %d >>\n", ret);
1224 fflush(stderr);
1225 }
1226
1227 return ret;
1228}
1229PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */
1230 return sem_wait_WRK(sem);
1231}
1232PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */
1233 return sem_wait_WRK(sem);
1234}
1235
1236
1237/* glibc-2.5 has sem_post (amd64-linux); match sem_post
1238 and sem_post@@GLIBC_2.1 (x86-linux); match sem_post@* */
1239/* post: increment semaphore - release lockage */
1240static int sem_post_WRK(sem_t* sem)
1241{
1242 OrigFn fn;
1243 int ret;
1244
1245 VALGRIND_GET_ORIG_FN(fn);
1246
1247 if (TRACE_SEM_FNS) {
1248 fprintf(stderr, "<< sem_post(%p) ", sem);
1249 fflush(stderr);
1250 }
1251
sewardj11e352f2007-11-30 11:11:02 +00001252 DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE, sem_t*,sem);
sewardjb4112022007-11-09 22:49:28 +00001253
1254 CALL_FN_W_W(ret, fn, sem);
1255
1256 if (ret != 0) {
1257 DO_PthAPIerror( "sem_post", errno );
1258 }
1259
1260 if (TRACE_SEM_FNS) {
1261 fprintf(stderr, " sem_post -> %d >>\n", ret);
1262 fflush(stderr);
1263 }
1264
1265 return ret;
1266}
1267PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
1268 return sem_post_WRK(sem);
1269}
1270PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */
1271 return sem_post_WRK(sem);
1272}
1273
1274
1275
1276/*----------------------------------------------------------------*/
1277/*--- Qt 4 threading functions (w/ GNU name mangling) ---*/
1278/*----------------------------------------------------------------*/
1279
sewardj38e0cf92008-11-19 10:40:56 +00001280/* Handled:
1281 QMutex::lock()
1282 QMutex::unlock()
1283 QMutex::tryLock()
1284 QMutex::tryLock(int)
sewardjb4112022007-11-09 22:49:28 +00001285
sewardj38e0cf92008-11-19 10:40:56 +00001286 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC1ENS_13RecursionModeE
1287 QMutex::QMutex(QMutex::RecursionMode) _ZN6QMutexC2ENS_13RecursionModeE
1288 QMutex::~QMutex() _ZN6QMutexD1Ev
1289 QMutex::~QMutex() _ZN6QMutexD2Ev
sewardjb4112022007-11-09 22:49:28 +00001290
sewardj38e0cf92008-11-19 10:40:56 +00001291 Unhandled:
1292 QReadWriteLock::lockForRead()
1293 QReadWriteLock::lockForWrite()
1294 QReadWriteLock::unlock()
1295 QReadWriteLock::tryLockForRead(int)
1296 QReadWriteLock::tryLockForRead()
1297 QReadWriteLock::tryLockForWrite(int)
1298 QReadWriteLock::tryLockForWrite()
1299
1300 QWaitCondition::wait(QMutex*, unsigned long)
1301 QWaitCondition::wakeAll()
1302 QWaitCondition::wakeOne()
1303
1304 QSemaphore::*
1305*/
1306/* More comments, 19 Nov 08, based on assessment of qt-4.5.0TP1,
1307 at least on Unix:
1308
1309 It's apparently only necessary to intercept QMutex, since that is
1310 not implemented using pthread_mutex_t; instead Qt4 has its own
1311 implementation based on atomics (to check the non-contended case)
1312 and pthread_cond_wait (to wait in the contended case).
1313
1314 QReadWriteLock is built on top of QMutex, counters, and a wait
1315 queue. So we don't need to handle it specially once QMutex
1316 handling is correct -- presumably the dependencies through QMutex
1317 are sufficient to avoid any false race reports. On the other hand,
1318 it is an open question whether too many dependencies are observed
1319 -- in which case we may miss races (false negatives). I suspect
1320 this is likely to be the case, unfortunately.
1321
1322 QWaitCondition is built on pthread_cond_t, pthread_mutex_t, QMutex
1323 and QReadWriteLock. Same compositional-correctness justificiation
1324 and limitations as fro QReadWriteLock.
1325
1326 Ditto QSemaphore (from cursory examination).
1327
1328 Does it matter that only QMutex is handled directly? Open
1329 question. From testing with drd/tests/qt4_* and with KDE4 apps, it
1330 appears that no false errors are reported; however it is not clear
1331 if this is causing false negatives.
1332
1333 Another problem with Qt4 is thread exiting. Threads are created
1334 with pthread_create (fine); but they detach and simply exit when
1335 done. There is no use of pthread_join, and the provided
1336 wait-for-a-thread-to-exit mechanism (QThread::wait, I believe)
1337 relies on a system of mutexes and flags. I suspect this also
1338 causes too many dependencies to appear. Consequently H sometimes
1339 fails to detect races at exit in some very short-lived racy
1340 programs, because it appears that a thread can exit _and_ have an
1341 observed dependency edge back to the main thread (presumably)
1342 before the main thread reaps the child (that is, calls
1343 QThread::wait).
1344
1345 This theory is supported by the observation that if all threads are
1346 made to wait at a pthread_barrier_t immediately before they exit,
1347 then H's detection of races in such programs becomes reliable;
1348 without the barrier, it is varies from run to run, depending
1349 (according to investigation) on whether aforementioned
1350 exit-before-reaping behaviour happens or not.
1351
1352 Finally, why is it necessary to intercept the QMutex constructors
1353 and destructors? The constructors are intercepted only as a matter
1354 of convenience, so H can print accurate "first observed at"
1355 clauses. However, it is actually necessary to intercept the
1356 destructors (as it is with pthread_mutex_destroy) in order that
1357 locks get removed from LAOG when they are destroyed.
sewardjb4112022007-11-09 22:49:28 +00001358*/
1359
1360// soname is libQtCore.so.4 ; match against libQtCore.so*
1361#define QT4_FUNC(ret_ty, f, args...) \
sewardj38e0cf92008-11-19 10:40:56 +00001362 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args); \
1363 ret_ty I_WRAP_SONAME_FNNAME_ZU(libQtCoreZdsoZa,f)(args)
sewardjb4112022007-11-09 22:49:28 +00001364
1365// QMutex::lock()
sewardj38e0cf92008-11-19 10:40:56 +00001366QT4_FUNC(void, _ZN6QMutex4lockEv, void* self)
sewardjb4112022007-11-09 22:49:28 +00001367{
1368 OrigFn fn;
1369 VALGRIND_GET_ORIG_FN(fn);
1370 if (TRACE_QT4_FNS) {
1371 fprintf(stderr, "<< QMutex::lock %p", self); fflush(stderr);
1372 }
1373
1374 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1375 void*,self, long,0/*!isTryLock*/);
1376
1377 CALL_FN_v_W(fn, self);
1378
1379 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1380 void*, self);
1381
1382 if (TRACE_QT4_FNS) {
1383 fprintf(stderr, " :: Q::lock done >>\n");
1384 }
1385}
1386
1387// QMutex::unlock()
sewardj38e0cf92008-11-19 10:40:56 +00001388QT4_FUNC(void, _ZN6QMutex6unlockEv, void* self)
sewardjb4112022007-11-09 22:49:28 +00001389{
1390 OrigFn fn;
1391 VALGRIND_GET_ORIG_FN(fn);
1392
1393 if (TRACE_QT4_FNS) {
1394 fprintf(stderr, "<< QMutex::unlock %p", self); fflush(stderr);
1395 }
1396
1397 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
1398 void*, self);
1399
1400 CALL_FN_v_W(fn, self);
1401
1402 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
1403 void*, self);
1404
1405 if (TRACE_QT4_FNS) {
1406 fprintf(stderr, " Q::unlock done >>\n");
1407 }
1408}
1409
sewardj38e0cf92008-11-19 10:40:56 +00001410// bool QMutex::tryLock()
sewardjb4112022007-11-09 22:49:28 +00001411// using 'long' to mimic C++ 'bool'
sewardj38e0cf92008-11-19 10:40:56 +00001412QT4_FUNC(long, _ZN6QMutex7tryLockEv, void* self)
sewardjb4112022007-11-09 22:49:28 +00001413{
1414 OrigFn fn;
1415 long ret;
1416 VALGRIND_GET_ORIG_FN(fn);
1417 if (TRACE_QT4_FNS) {
1418 fprintf(stderr, "<< QMutex::tryLock %p", self); fflush(stderr);
1419 }
1420
1421 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1422 void*,self, long,1/*isTryLock*/);
1423
1424 CALL_FN_W_W(ret, fn, self);
1425
1426 // assumes that only the low 8 bits of the 'bool' are significant
1427 if (ret & 0xFF) {
1428 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1429 void*, self);
1430 }
1431
1432 if (TRACE_QT4_FNS) {
1433 fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
1434 }
1435
1436 return ret;
1437}
1438
sewardj38e0cf92008-11-19 10:40:56 +00001439// bool QMutex::tryLock(int)
1440// using 'long' to mimic C++ 'bool'
1441QT4_FUNC(long, _ZN6QMutex7tryLockEi, void* self, long arg2)
sewardjb4112022007-11-09 22:49:28 +00001442{
1443 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00001444 long ret;
sewardjb4112022007-11-09 22:49:28 +00001445 VALGRIND_GET_ORIG_FN(fn);
1446 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00001447 fprintf(stderr, "<< QMutex::tryLock(int) %p %d", self, (int)arg2);
sewardjb4112022007-11-09 22:49:28 +00001448 fflush(stderr);
1449 }
1450
sewardj38e0cf92008-11-19 10:40:56 +00001451 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
1452 void*,self, long,1/*isTryLock*/);
sewardjb4112022007-11-09 22:49:28 +00001453
sewardj38e0cf92008-11-19 10:40:56 +00001454 CALL_FN_W_WW(ret, fn, self,arg2);
sewardjb4112022007-11-09 22:49:28 +00001455
sewardj38e0cf92008-11-19 10:40:56 +00001456 // assumes that only the low 8 bits of the 'bool' are significant
1457 if (ret & 0xFF) {
1458 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
1459 void*, self);
1460 }
sewardjb4112022007-11-09 22:49:28 +00001461
1462 if (TRACE_QT4_FNS) {
sewardj38e0cf92008-11-19 10:40:56 +00001463 fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
sewardjb4112022007-11-09 22:49:28 +00001464 }
sewardj38e0cf92008-11-19 10:40:56 +00001465
1466 return ret;
sewardjb4112022007-11-09 22:49:28 +00001467}
1468
sewardj38e0cf92008-11-19 10:40:56 +00001469
1470// It's not really very clear what the args are here. But from
1471// a bit of dataflow analysis of the generated machine code of
1472// the original function, it appears this takes two args, and
1473// returns nothing. Nevertheless preserve return value just in
1474// case. A bit of debug printing indicates that the first arg
1475// is that of the mutex and the second is either zero or one,
1476// probably being the recursion mode, therefore.
1477// QMutex::QMutex(QMutex::RecursionMode) ("C1ENS" variant)
1478QT4_FUNC(void*, _ZN6QMutexC1ENS_13RecursionModeE,
1479 void* mutex,
1480 long recmode)
sewardjb4112022007-11-09 22:49:28 +00001481{
1482 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00001483 long ret;
sewardjb4112022007-11-09 22:49:28 +00001484 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00001485 CALL_FN_W_WW(ret, fn, mutex, recmode);
1486 // fprintf(stderr, "QMutex constructor 1: %p <- %p %p\n", ret, arg1, arg2);
1487 DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
1488 void*,mutex, long,1/*mbRec*/);
1489 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00001490}
1491
sewardj38e0cf92008-11-19 10:40:56 +00001492// QMutex::~QMutex() ("D1Ev" variant)
1493QT4_FUNC(void*, _ZN6QMutexD1Ev, void* mutex)
sewardjb4112022007-11-09 22:49:28 +00001494{
1495 OrigFn fn;
sewardj38e0cf92008-11-19 10:40:56 +00001496 long ret;
sewardjb4112022007-11-09 22:49:28 +00001497 VALGRIND_GET_ORIG_FN(fn);
sewardj38e0cf92008-11-19 10:40:56 +00001498 DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,
1499 void*,mutex);
1500 CALL_FN_W_W(ret, fn, mutex);
1501 return (void*)ret;
sewardjb4112022007-11-09 22:49:28 +00001502}
1503
1504
sewardj38e0cf92008-11-19 10:40:56 +00001505// QMutex::QMutex(QMutex::RecursionMode) ("C2ENS" variant)
1506QT4_FUNC(void*, _ZN6QMutexC2ENS_13RecursionModeE,
1507 void* mutex,
1508 long recmode)
1509{
1510 assert(0);
1511}
1512
1513// QMutex::~QMutex() ("D2Ev" variant)
1514QT4_FUNC(void*, _ZN6QMutexD2Ev, void* mutex)
1515{
1516 assert(0);
1517}
1518
1519
1520// QReadWriteLock is not intercepted directly. See comments
1521// above.
1522
1523//// QReadWriteLock::lockForRead()
1524//// _ZN14QReadWriteLock11lockForReadEv == QReadWriteLock::lockForRead()
1525//QT4_FUNC(void, ZuZZN14QReadWriteLock11lockForReadEv,
1526// // _ZN14QReadWriteLock11lockForReadEv
1527// void* self)
1528//{
1529// OrigFn fn;
1530// VALGRIND_GET_ORIG_FN(fn);
1531// if (TRACE_QT4_FNS) {
1532// fprintf(stderr, "<< QReadWriteLock::lockForRead %p", self);
1533// fflush(stderr);
1534// }
1535//
1536// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1537// void*,self,
1538// long,0/*!isW*/, long,0/*!isTryLock*/);
1539//
1540// CALL_FN_v_W(fn, self);
1541//
1542// DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1543// void*,self, long,0/*!isW*/);
1544//
1545// if (TRACE_QT4_FNS) {
1546// fprintf(stderr, " :: Q::lockForRead :: done >>\n");
1547// }
1548//}
1549//
1550//// QReadWriteLock::lockForWrite()
1551//// _ZN14QReadWriteLock12lockForWriteEv == QReadWriteLock::lockForWrite()
1552//QT4_FUNC(void, ZuZZN14QReadWriteLock12lockForWriteEv,
1553// // _ZN14QReadWriteLock12lockForWriteEv
1554// void* self)
1555//{
1556// OrigFn fn;
1557// VALGRIND_GET_ORIG_FN(fn);
1558// if (TRACE_QT4_FNS) {
1559// fprintf(stderr, "<< QReadWriteLock::lockForWrite %p", self);
1560// fflush(stderr);
1561// }
1562//
1563// DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
1564// void*,self,
1565// long,1/*isW*/, long,0/*!isTryLock*/);
1566//
1567// CALL_FN_v_W(fn, self);
1568//
1569// DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
1570// void*,self, long,1/*isW*/);
1571//
1572// if (TRACE_QT4_FNS) {
1573// fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
1574// }
1575//}
1576//
1577//// QReadWriteLock::unlock()
1578//// _ZN14QReadWriteLock6unlockEv == QReadWriteLock::unlock()
1579//QT4_FUNC(void, ZuZZN14QReadWriteLock6unlockEv,
1580// // _ZN14QReadWriteLock6unlockEv
1581// void* self)
1582//{
1583// OrigFn fn;
1584// VALGRIND_GET_ORIG_FN(fn);
1585// if (TRACE_QT4_FNS) {
1586// fprintf(stderr, "<< QReadWriteLock::unlock %p", self);
1587// fflush(stderr);
1588// }
1589//
1590// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,
1591// void*,self);
1592//
1593// CALL_FN_v_W(fn, self);
1594//
1595// DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
1596// void*,self);
1597//
1598// if (TRACE_QT4_FNS) {
1599// fprintf(stderr, " :: Q::unlock :: done >>\n");
1600// }
1601//}
1602
1603
1604/*----------------------------------------------------------------*/
1605/*--- Replacements for basic string functions, that don't ---*/
sewardjb80f0c92008-11-19 16:33:59 +00001606/*--- overrun the input arrays. ---*/
sewardj38e0cf92008-11-19 10:40:56 +00001607/*----------------------------------------------------------------*/
1608
1609/* Copied verbatim from memcheck/mc_replace_strmem.c. When copying
1610 new functions, please keep them in the same order as they appear in
1611 mc_replace_strmem.c. */
1612
sewardj38e0cf92008-11-19 10:40:56 +00001613
1614#define STRCHR(soname, fnname) \
1615 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \
1616 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \
1617 { \
1618 UChar ch = (UChar)((UInt)c); \
1619 UChar* p = (UChar*)s; \
1620 while (True) { \
1621 if (*p == ch) return p; \
1622 if (*p == 0) return NULL; \
1623 p++; \
1624 } \
1625 }
1626
1627// Apparently index() is the same thing as strchr()
njne6154662009-02-10 04:23:41 +00001628STRCHR(VG_Z_LIBC_SONAME, strchr)
njne6154662009-02-10 04:23:41 +00001629STRCHR(VG_Z_LIBC_SONAME, index)
njnb4cfbc42009-05-04 04:20:02 +00001630#if defined(VGO_linux)
1631STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
njne6154662009-02-10 04:23:41 +00001632STRCHR(VG_Z_LD_LINUX_SO_2, index)
njnb4cfbc42009-05-04 04:20:02 +00001633STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
njne6154662009-02-10 04:23:41 +00001634STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
njnb4cfbc42009-05-04 04:20:02 +00001635#endif
sewardj38e0cf92008-11-19 10:40:56 +00001636
1637
1638// Note that this replacement often doesn't get used because gcc inlines
1639// calls to strlen() with its own built-in version. This can be very
1640// confusing if you aren't expecting it. Other small functions in this file
1641// may also be inline by gcc.
1642#define STRLEN(soname, fnname) \
1643 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
1644 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
1645 { \
1646 SizeT i = 0; \
1647 while (str[i] != 0) i++; \
1648 return i; \
1649 }
1650
njne6154662009-02-10 04:23:41 +00001651STRLEN(VG_Z_LIBC_SONAME, strlen)
njnb4cfbc42009-05-04 04:20:02 +00001652#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +00001653STRLEN(VG_Z_LD_LINUX_SO_2, strlen)
1654STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
njnb4cfbc42009-05-04 04:20:02 +00001655#endif
sewardj38e0cf92008-11-19 10:40:56 +00001656
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
njne6154662009-02-10 04:23:41 +00001670STRCPY(VG_Z_LIBC_SONAME, strcpy)
sewardj38e0cf92008-11-19 10:40:56 +00001671
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
njne6154662009-02-10 04:23:41 +00001693STRCMP(VG_Z_LIBC_SONAME, strcmp)
njnb4cfbc42009-05-04 04:20:02 +00001694#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +00001695STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
1696STRCMP(VG_Z_LD64_SO_1, strcmp)
njnb4cfbc42009-05-04 04:20:02 +00001697#endif
sewardj38e0cf92008-11-19 10:40:56 +00001698
1699
1700#define MEMCPY(soname, fnname) \
1701 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1702 ( void *dst, const void *src, SizeT len ); \
1703 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1704 ( void *dst, const void *src, SizeT len ) \
1705 { \
1706 register char *d; \
1707 register char *s; \
1708 \
1709 if (len == 0) \
1710 return dst; \
1711 \
1712 if ( dst > src ) { \
1713 d = (char *)dst + len - 1; \
1714 s = (char *)src + len - 1; \
1715 while ( len >= 4 ) { \
1716 *d-- = *s--; \
1717 *d-- = *s--; \
1718 *d-- = *s--; \
1719 *d-- = *s--; \
1720 len -= 4; \
1721 } \
1722 while ( len-- ) { \
1723 *d-- = *s--; \
1724 } \
1725 } else if ( dst < src ) { \
1726 d = (char *)dst; \
1727 s = (char *)src; \
1728 while ( len >= 4 ) { \
1729 *d++ = *s++; \
1730 *d++ = *s++; \
1731 *d++ = *s++; \
1732 *d++ = *s++; \
1733 len -= 4; \
1734 } \
1735 while ( len-- ) { \
1736 *d++ = *s++; \
1737 } \
1738 } \
1739 return dst; \
1740 }
1741
njne6154662009-02-10 04:23:41 +00001742MEMCPY(VG_Z_LIBC_SONAME, memcpy)
njnb4cfbc42009-05-04 04:20:02 +00001743#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +00001744MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
1745MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
njnb4cfbc42009-05-04 04:20:02 +00001746#endif
sewardj38e0cf92008-11-19 10:40:56 +00001747/* icc9 blats these around all over the place. Not only in the main
1748 executable but various .so's. They are highly tuned and read
1749 memory beyond the source boundary (although work correctly and
1750 never go across page boundaries), so give errors when run natively,
1751 at least for misaligned source arg. Just intercepting in the exe
1752 only until we understand more about the problem. See
1753 http://bugs.kde.org/show_bug.cgi?id=139776
1754 */
1755MEMCPY(NONE, _intel_fast_memcpy)
1756
1757
sewardjb4112022007-11-09 22:49:28 +00001758/*--------------------------------------------------------------------*/
1759/*--- end tc_intercepts.c ---*/
1760/*--------------------------------------------------------------------*/