1
2 /*--------------------------------------------------------------------*/
3 /*--- Helgrind: a Valgrind tool for detecting errors ---*/
4 /*--- in threaded programs. hg_main.c ---*/
5 /*--------------------------------------------------------------------*/
6
7 /*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
11 Copyright (C) 2007-2013 OpenWorks LLP
12 info@open-works.co.uk
13
14 Copyright (C) 2007-2013 Apple, Inc.
15
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation; either version 2 of the
19 License, or (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 02111-1307, USA.
30
31 The GNU General Public License is contained in the file COPYING.
32
33 Neither the names of the U.S. Department of Energy nor the
34 University of California nor the names of its contributors may be
35 used to endorse or promote products derived from this software
36 without prior written permission.
37 */
38
39 #include "pub_tool_basics.h"
40 #include "pub_tool_gdbserver.h"
41 #include "pub_tool_libcassert.h"
42 #include "pub_tool_libcbase.h"
43 #include "pub_tool_libcprint.h"
44 #include "pub_tool_threadstate.h"
45 #include "pub_tool_tooliface.h"
46 #include "pub_tool_hashtable.h"
47 #include "pub_tool_replacemalloc.h"
48 #include "pub_tool_machine.h"
49 #include "pub_tool_options.h"
50 #include "pub_tool_xarray.h"
51 #include "pub_tool_stacktrace.h"
52 #include "pub_tool_wordfm.h"
53 #include "pub_tool_debuginfo.h" // VG_(find_seginfo), VG_(seginfo_soname)
54 #include "pub_tool_redir.h" // sonames for the dynamic linkers
55 #include "pub_tool_vki.h" // VKI_PAGE_SIZE
56 #include "pub_tool_libcproc.h" // VG_(atfork)
57 #include "pub_tool_aspacemgr.h" // VG_(am_is_valid_for_client)
58 #include "pub_tool_poolalloc.h"
59 #include "pub_tool_addrinfo.h"
60
61 #include "hg_basics.h"
62 #include "hg_wordset.h"
63 #include "hg_addrdescr.h"
64 #include "hg_lock_n_thread.h"
65 #include "hg_errors.h"
66
67 #include "libhb.h"
68
69 #include "helgrind.h"
70
71
72 // FIXME: new_mem_w_tid ignores the supplied tid. (wtf?!)
73
74 // FIXME: when client destroys a lock or a CV, remove these
75 // from our mappings, so that the associated SO can be freed up
76
77 /*----------------------------------------------------------------*/
78 /*--- ---*/
79 /*----------------------------------------------------------------*/
80
81 /* Note this needs to be compiled with -fno-strict-aliasing, since it
82 contains a whole bunch of calls to lookupFM etc which cast between
83 Word and pointer types. gcc rightly complains this breaks ANSI C
84 strict aliasing rules, at -O2. No complaints at -O, but -O2 gives
85 worthwhile performance benefits over -O.
86 */
87
88 // FIXME what is supposed to happen to locks in memory which
89 // is relocated as a result of client realloc?
90
91 // FIXME put referencing ThreadId into Thread and get
92 // rid of the slow reverse mapping function.
93
94 // FIXME accesses to NoAccess areas: change state to Excl?
95
96 // FIXME report errors for accesses of NoAccess memory?
97
98 // FIXME pth_cond_wait/timedwait wrappers. Even if these fail,
99 // the thread still holds the lock.
100
101 /* ------------ Debug/trace options ------------ */
102
103 // 0 for silent, 1 for some stuff, 2 for lots of stuff
104 #define SHOW_EVENTS 0
105
106
107 static void all__sanity_check ( const HChar* who ); /* fwds */
108
109 #define HG_CLI__DEFAULT_MALLOC_REDZONE_SZB 16 /* let's say */
110
111 // 0 for none, 1 for dump at end of run
112 #define SHOW_DATA_STRUCTURES 0
113
114
115 /* ------------ Misc comments ------------ */
116
117 // FIXME: don't hardwire initial entries for root thread.
118 // Instead, let the pre_thread_ll_create handler do this.
119
120
121 /*----------------------------------------------------------------*/
122 /*--- Primary data structures ---*/
123 /*----------------------------------------------------------------*/
124
125 /* Admin linked list of Threads */
126 static Thread* admin_threads = NULL;
get_admin_threads(void)127 Thread* get_admin_threads ( void ) { return admin_threads; }
128
129 /* Admin double linked list of Locks */
130 /* We need a double linked list to properly and efficiently
131 handle del_LockN. */
132 static Lock* admin_locks = NULL;
133
134 /* Mapping table for core ThreadIds to Thread* */
135 static Thread** map_threads = NULL; /* Array[VG_N_THREADS] of Thread* */
136
137 /* Mapping table for lock guest addresses to Lock* */
138 static WordFM* map_locks = NULL; /* WordFM LockAddr Lock* */
139
140 /* The word-set universes for lock sets. */
141 static WordSetU* univ_lsets = NULL; /* sets of Lock* */
142 static WordSetU* univ_laog = NULL; /* sets of Lock*, for LAOG */
143 static Int next_gc_univ_laog = 1;
144 /* univ_laog will be garbaged collected when the nr of element in univ_laog is
145 >= next_gc_univ_laog. */
146
147 /* Allow libhb to get at the universe of locksets stored
148 here. Sigh. */
HG_(get_univ_lsets)149 WordSetU* HG_(get_univ_lsets) ( void ) { return univ_lsets; }
150
151 /* Allow libhb to get at the list of locks stored here. Ditto
152 sigh. */
HG_(get_admin_locks)153 Lock* HG_(get_admin_locks) ( void ) { return admin_locks; }
154
155
156 /*----------------------------------------------------------------*/
157 /*--- Simple helpers for the data structures ---*/
158 /*----------------------------------------------------------------*/
159
160 static UWord stats__lockN_acquires = 0;
161 static UWord stats__lockN_releases = 0;
162
163 static
164 ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr ); /*fwds*/
165
166 /* --------- Constructors --------- */
167
mk_Thread(Thr * hbthr)168 static Thread* mk_Thread ( Thr* hbthr ) {
169 static Int indx = 1;
170 Thread* thread = HG_(zalloc)( "hg.mk_Thread.1", sizeof(Thread) );
171 thread->locksetA = HG_(emptyWS)( univ_lsets );
172 thread->locksetW = HG_(emptyWS)( univ_lsets );
173 thread->magic = Thread_MAGIC;
174 thread->hbthr = hbthr;
175 thread->coretid = VG_INVALID_THREADID;
176 thread->created_at = NULL;
177 thread->announced = False;
178 thread->errmsg_index = indx++;
179 thread->admin = admin_threads;
180 admin_threads = thread;
181 return thread;
182 }
183
184 // Make a new lock which is unlocked (hence ownerless)
185 // and insert the new lock in admin_locks double linked list.
mk_LockN(LockKind kind,Addr guestaddr)186 static Lock* mk_LockN ( LockKind kind, Addr guestaddr ) {
187 static ULong unique = 0;
188 Lock* lock = HG_(zalloc)( "hg.mk_Lock.1", sizeof(Lock) );
189 /* begin: add to double linked list */
190 if (admin_locks)
191 admin_locks->admin_prev = lock;
192 lock->admin_next = admin_locks;
193 lock->admin_prev = NULL;
194 admin_locks = lock;
195 /* end: add */
196 lock->unique = unique++;
197 lock->magic = LockN_MAGIC;
198 lock->appeared_at = NULL;
199 lock->acquired_at = NULL;
200 lock->hbso = libhb_so_alloc();
201 lock->guestaddr = guestaddr;
202 lock->kind = kind;
203 lock->heldW = False;
204 lock->heldBy = NULL;
205 tl_assert(HG_(is_sane_LockN)(lock));
206 return lock;
207 }
208
209 /* Release storage for a Lock. Also release storage in .heldBy, if
210 any. Removes from admin_locks double linked list. */
del_LockN(Lock * lk)211 static void del_LockN ( Lock* lk )
212 {
213 tl_assert(HG_(is_sane_LockN)(lk));
214 tl_assert(lk->hbso);
215 libhb_so_dealloc(lk->hbso);
216 if (lk->heldBy)
217 VG_(deleteBag)( lk->heldBy );
218 /* begin: del lock from double linked list */
219 if (lk == admin_locks) {
220 tl_assert(lk->admin_prev == NULL);
221 if (lk->admin_next)
222 lk->admin_next->admin_prev = NULL;
223 admin_locks = lk->admin_next;
224 }
225 else {
226 tl_assert(lk->admin_prev != NULL);
227 lk->admin_prev->admin_next = lk->admin_next;
228 if (lk->admin_next)
229 lk->admin_next->admin_prev = lk->admin_prev;
230 }
231 /* end: del */
232 VG_(memset)(lk, 0xAA, sizeof(*lk));
233 HG_(free)(lk);
234 }
235
236 /* Update 'lk' to reflect that 'thr' now has a write-acquisition of
237 it. This is done strictly: only combinations resulting from
238 correct program and libpthread behaviour are allowed. */
lockN_acquire_writer(Lock * lk,Thread * thr)239 static void lockN_acquire_writer ( Lock* lk, Thread* thr )
240 {
241 tl_assert(HG_(is_sane_LockN)(lk));
242 tl_assert(HG_(is_sane_Thread)(thr));
243
244 stats__lockN_acquires++;
245
246 /* EXPOSITION only */
247 /* We need to keep recording snapshots of where the lock was
248 acquired, so as to produce better lock-order error messages. */
249 if (lk->acquired_at == NULL) {
250 ThreadId tid;
251 tl_assert(lk->heldBy == NULL);
252 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
253 lk->acquired_at
254 = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
255 } else {
256 tl_assert(lk->heldBy != NULL);
257 }
258 /* end EXPOSITION only */
259
260 switch (lk->kind) {
261 case LK_nonRec:
262 case_LK_nonRec:
263 tl_assert(lk->heldBy == NULL); /* can't w-lock recursively */
264 tl_assert(!lk->heldW);
265 lk->heldW = True;
266 lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNaw.1", HG_(free) );
267 VG_(addToBag)( lk->heldBy, (UWord)thr );
268 break;
269 case LK_mbRec:
270 if (lk->heldBy == NULL)
271 goto case_LK_nonRec;
272 /* 2nd and subsequent locking of a lock by its owner */
273 tl_assert(lk->heldW);
274 /* assert: lk is only held by one thread .. */
275 tl_assert(VG_(sizeUniqueBag(lk->heldBy)) == 1);
276 /* assert: .. and that thread is 'thr'. */
277 tl_assert(VG_(elemBag)(lk->heldBy, (UWord)thr)
278 == VG_(sizeTotalBag)(lk->heldBy));
279 VG_(addToBag)(lk->heldBy, (UWord)thr);
280 break;
281 case LK_rdwr:
282 tl_assert(lk->heldBy == NULL && !lk->heldW); /* must be unheld */
283 goto case_LK_nonRec;
284 default:
285 tl_assert(0);
286 }
287 tl_assert(HG_(is_sane_LockN)(lk));
288 }
289
lockN_acquire_reader(Lock * lk,Thread * thr)290 static void lockN_acquire_reader ( Lock* lk, Thread* thr )
291 {
292 tl_assert(HG_(is_sane_LockN)(lk));
293 tl_assert(HG_(is_sane_Thread)(thr));
294 /* can only add reader to a reader-writer lock. */
295 tl_assert(lk->kind == LK_rdwr);
296 /* lk must be free or already r-held. */
297 tl_assert(lk->heldBy == NULL
298 || (lk->heldBy != NULL && !lk->heldW));
299
300 stats__lockN_acquires++;
301
302 /* EXPOSITION only */
303 /* We need to keep recording snapshots of where the lock was
304 acquired, so as to produce better lock-order error messages. */
305 if (lk->acquired_at == NULL) {
306 ThreadId tid;
307 tl_assert(lk->heldBy == NULL);
308 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
309 lk->acquired_at
310 = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
311 } else {
312 tl_assert(lk->heldBy != NULL);
313 }
314 /* end EXPOSITION only */
315
316 if (lk->heldBy) {
317 VG_(addToBag)(lk->heldBy, (UWord)thr);
318 } else {
319 lk->heldW = False;
320 lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNar.1", HG_(free) );
321 VG_(addToBag)( lk->heldBy, (UWord)thr );
322 }
323 tl_assert(!lk->heldW);
324 tl_assert(HG_(is_sane_LockN)(lk));
325 }
326
327 /* Update 'lk' to reflect a release of it by 'thr'. This is done
328 strictly: only combinations resulting from correct program and
329 libpthread behaviour are allowed. */
330
lockN_release(Lock * lk,Thread * thr)331 static void lockN_release ( Lock* lk, Thread* thr )
332 {
333 Bool b;
334 tl_assert(HG_(is_sane_LockN)(lk));
335 tl_assert(HG_(is_sane_Thread)(thr));
336 /* lock must be held by someone */
337 tl_assert(lk->heldBy);
338 stats__lockN_releases++;
339 /* Remove it from the holder set */
340 b = VG_(delFromBag)(lk->heldBy, (UWord)thr);
341 /* thr must actually have been a holder of lk */
342 tl_assert(b);
343 /* normalise */
344 tl_assert(lk->acquired_at);
345 if (VG_(isEmptyBag)(lk->heldBy)) {
346 VG_(deleteBag)(lk->heldBy);
347 lk->heldBy = NULL;
348 lk->heldW = False;
349 lk->acquired_at = NULL;
350 }
351 tl_assert(HG_(is_sane_LockN)(lk));
352 }
353
remove_Lock_from_locksets_of_all_owning_Threads(Lock * lk)354 static void remove_Lock_from_locksets_of_all_owning_Threads( Lock* lk )
355 {
356 Thread* thr;
357 if (!lk->heldBy) {
358 tl_assert(!lk->heldW);
359 return;
360 }
361 /* for each thread that holds this lock do ... */
362 VG_(initIterBag)( lk->heldBy );
363 while (VG_(nextIterBag)( lk->heldBy, (UWord*)&thr, NULL )) {
364 tl_assert(HG_(is_sane_Thread)(thr));
365 tl_assert(HG_(elemWS)( univ_lsets,
366 thr->locksetA, (UWord)lk ));
367 thr->locksetA
368 = HG_(delFromWS)( univ_lsets, thr->locksetA, (UWord)lk );
369
370 if (lk->heldW) {
371 tl_assert(HG_(elemWS)( univ_lsets,
372 thr->locksetW, (UWord)lk ));
373 thr->locksetW
374 = HG_(delFromWS)( univ_lsets, thr->locksetW, (UWord)lk );
375 }
376 }
377 VG_(doneIterBag)( lk->heldBy );
378 }
379
380
381 /*----------------------------------------------------------------*/
382 /*--- Print out the primary data structures ---*/
383 /*----------------------------------------------------------------*/
384
385 #define PP_THREADS (1<<1)
386 #define PP_LOCKS (1<<2)
387 #define PP_ALL (PP_THREADS | PP_LOCKS)
388
389
390 static const Int sHOW_ADMIN = 0;
391
space(Int n)392 static void space ( Int n )
393 {
394 Int i;
395 HChar spaces[128+1];
396 tl_assert(n >= 0 && n < 128);
397 if (n == 0)
398 return;
399 for (i = 0; i < n; i++)
400 spaces[i] = ' ';
401 spaces[i] = 0;
402 tl_assert(i < 128+1);
403 VG_(printf)("%s", spaces);
404 }
405
pp_Thread(Int d,Thread * t)406 static void pp_Thread ( Int d, Thread* t )
407 {
408 space(d+0); VG_(printf)("Thread %p {\n", t);
409 if (sHOW_ADMIN) {
410 space(d+3); VG_(printf)("admin %p\n", t->admin);
411 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)t->magic);
412 }
413 space(d+3); VG_(printf)("locksetA %d\n", (Int)t->locksetA);
414 space(d+3); VG_(printf)("locksetW %d\n", (Int)t->locksetW);
415 space(d+0); VG_(printf)("}\n");
416 }
417
pp_admin_threads(Int d)418 static void pp_admin_threads ( Int d )
419 {
420 Int i, n;
421 Thread* t;
422 for (n = 0, t = admin_threads; t; n++, t = t->admin) {
423 /* nothing */
424 }
425 space(d); VG_(printf)("admin_threads (%d records) {\n", n);
426 for (i = 0, t = admin_threads; t; i++, t = t->admin) {
427 if (0) {
428 space(n);
429 VG_(printf)("admin_threads record %d of %d:\n", i, n);
430 }
431 pp_Thread(d+3, t);
432 }
433 space(d); VG_(printf)("}\n");
434 }
435
pp_map_threads(Int d)436 static void pp_map_threads ( Int d )
437 {
438 Int i, n = 0;
439 space(d); VG_(printf)("map_threads ");
440 for (i = 0; i < VG_N_THREADS; i++) {
441 if (map_threads[i] != NULL)
442 n++;
443 }
444 VG_(printf)("(%d entries) {\n", n);
445 for (i = 0; i < VG_N_THREADS; i++) {
446 if (map_threads[i] == NULL)
447 continue;
448 space(d+3);
449 VG_(printf)("coretid %d -> Thread %p\n", i, map_threads[i]);
450 }
451 space(d); VG_(printf)("}\n");
452 }
453
show_LockKind(LockKind lkk)454 static const HChar* show_LockKind ( LockKind lkk ) {
455 switch (lkk) {
456 case LK_mbRec: return "mbRec";
457 case LK_nonRec: return "nonRec";
458 case LK_rdwr: return "rdwr";
459 default: tl_assert(0);
460 }
461 }
462
463 /* Pretty Print lock lk.
464 if show_lock_addrdescr, describes the (guest) lock address.
465 (this description will be more complete with --read-var-info=yes).
466 if show_internal_data, shows also helgrind internal information.
467 d is the level at which output is indented. */
pp_Lock(Int d,Lock * lk,Bool show_lock_addrdescr,Bool show_internal_data)468 static void pp_Lock ( Int d, Lock* lk,
469 Bool show_lock_addrdescr,
470 Bool show_internal_data)
471 {
472 space(d+0);
473 if (show_internal_data)
474 VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr);
475 else
476 VG_(printf)("Lock ga %#lx {\n", lk->guestaddr);
477 if (!show_lock_addrdescr
478 || !HG_(get_and_pp_addrdescr) ((Addr) lk->guestaddr))
479 VG_(printf)("\n");
480
481 if (sHOW_ADMIN) {
482 space(d+3); VG_(printf)("admin_n %p\n", lk->admin_next);
483 space(d+3); VG_(printf)("admin_p %p\n", lk->admin_prev);
484 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)lk->magic);
485 }
486 if (show_internal_data) {
487 space(d+3); VG_(printf)("unique %llu\n", lk->unique);
488 }
489 space(d+3); VG_(printf)("kind %s\n", show_LockKind(lk->kind));
490 if (show_internal_data) {
491 space(d+3); VG_(printf)("heldW %s\n", lk->heldW ? "yes" : "no");
492 }
493 if (show_internal_data) {
494 space(d+3); VG_(printf)("heldBy %p", lk->heldBy);
495 }
496 if (lk->heldBy) {
497 Thread* thr;
498 UWord count;
499 VG_(printf)(" { ");
500 VG_(initIterBag)( lk->heldBy );
501 while (VG_(nextIterBag)( lk->heldBy, (UWord*)&thr, &count )) {
502 if (show_internal_data)
503 VG_(printf)("%lu:%p ", count, thr);
504 else {
505 VG_(printf)("%c%lu:thread #%d ",
506 lk->heldW ? 'W' : 'R',
507 count, thr->errmsg_index);
508 if (thr->coretid == VG_INVALID_THREADID)
509 VG_(printf)("tid (exited) ");
510 else
511 VG_(printf)("tid %d ", thr->coretid);
512
513 }
514 }
515 VG_(doneIterBag)( lk->heldBy );
516 VG_(printf)("}\n");
517 }
518 space(d+0); VG_(printf)("}\n");
519 }
520
pp_admin_locks(Int d)521 static void pp_admin_locks ( Int d )
522 {
523 Int i, n;
524 Lock* lk;
525 for (n = 0, lk = admin_locks; lk; n++, lk = lk->admin_next) {
526 /* nothing */
527 }
528 space(d); VG_(printf)("admin_locks (%d records) {\n", n);
529 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next) {
530 if (0) {
531 space(n);
532 VG_(printf)("admin_locks record %d of %d:\n", i, n);
533 }
534 pp_Lock(d+3, lk,
535 False /* show_lock_addrdescr */,
536 True /* show_internal_data */);
537 }
538 space(d); VG_(printf)("}\n");
539 }
540
pp_map_locks(Int d)541 static void pp_map_locks ( Int d)
542 {
543 void* gla;
544 Lock* lk;
545 space(d); VG_(printf)("map_locks (%d entries) {\n",
546 (Int)VG_(sizeFM)( map_locks ));
547 VG_(initIterFM)( map_locks );
548 while (VG_(nextIterFM)( map_locks, (UWord*)&gla,
549 (UWord*)&lk )) {
550 space(d+3);
551 VG_(printf)("guest %p -> Lock %p\n", gla, lk);
552 }
553 VG_(doneIterFM)( map_locks );
554 space(d); VG_(printf)("}\n");
555 }
556
pp_everything(Int flags,const HChar * caller)557 static void pp_everything ( Int flags, const HChar* caller )
558 {
559 Int d = 0;
560 VG_(printf)("\n");
561 VG_(printf)("All_Data_Structures (caller = \"%s\") {\n", caller);
562 if (flags & PP_THREADS) {
563 VG_(printf)("\n");
564 pp_admin_threads(d+3);
565 VG_(printf)("\n");
566 pp_map_threads(d+3);
567 }
568 if (flags & PP_LOCKS) {
569 VG_(printf)("\n");
570 pp_admin_locks(d+3);
571 VG_(printf)("\n");
572 pp_map_locks(d+3);
573 }
574
575 VG_(printf)("\n");
576 VG_(printf)("}\n");
577 VG_(printf)("\n");
578 }
579
580 #undef SHOW_ADMIN
581
582
583 /*----------------------------------------------------------------*/
584 /*--- Initialise the primary data structures ---*/
585 /*----------------------------------------------------------------*/
586
initialise_data_structures(Thr * hbthr_root)587 static void initialise_data_structures ( Thr* hbthr_root )
588 {
589 Thread* thr;
590 WordSetID wsid;
591
592 /* Get everything initialised and zeroed. */
593 tl_assert(admin_threads == NULL);
594 tl_assert(admin_locks == NULL);
595
596 tl_assert(map_threads == NULL);
597 map_threads = HG_(zalloc)( "hg.ids.1", VG_N_THREADS * sizeof(Thread*) );
598
599 tl_assert(sizeof(Addr) == sizeof(UWord));
600 tl_assert(map_locks == NULL);
601 map_locks = VG_(newFM)( HG_(zalloc), "hg.ids.2", HG_(free),
602 NULL/*unboxed Word cmp*/);
603
604 tl_assert(univ_lsets == NULL);
605 univ_lsets = HG_(newWordSetU)( HG_(zalloc), "hg.ids.4", HG_(free),
606 8/*cacheSize*/ );
607 tl_assert(univ_lsets != NULL);
608 /* Ensure that univ_lsets is non-empty, with lockset zero being the
609 empty lockset. hg_errors.c relies on the assumption that
610 lockset number zero in univ_lsets is always valid. */
611 wsid = HG_(emptyWS)(univ_lsets);
612 tl_assert(wsid == 0);
613
614 tl_assert(univ_laog == NULL);
615 if (HG_(clo_track_lockorders)) {
616 univ_laog = HG_(newWordSetU)( HG_(zalloc), "hg.ids.5 (univ_laog)",
617 HG_(free), 24/*cacheSize*/ );
618 tl_assert(univ_laog != NULL);
619 }
620
621 /* Set up entries for the root thread */
622 // FIXME: this assumes that the first real ThreadId is 1
623
624 /* a Thread for the new thread ... */
625 thr = mk_Thread(hbthr_root);
626 thr->coretid = 1; /* FIXME: hardwires an assumption about the
627 identity of the root thread. */
628 tl_assert( libhb_get_Thr_hgthread(hbthr_root) == NULL );
629 libhb_set_Thr_hgthread(hbthr_root, thr);
630
631 /* and bind it in the thread-map table. */
632 tl_assert(HG_(is_sane_ThreadId)(thr->coretid));
633 tl_assert(thr->coretid != VG_INVALID_THREADID);
634
635 map_threads[thr->coretid] = thr;
636
637 tl_assert(VG_INVALID_THREADID == 0);
638
639 all__sanity_check("initialise_data_structures");
640 }
641
642
643 /*----------------------------------------------------------------*/
644 /*--- map_threads :: array[core-ThreadId] of Thread* ---*/
645 /*----------------------------------------------------------------*/
646
647 /* Doesn't assert if the relevant map_threads entry is NULL. */
map_threads_maybe_lookup(ThreadId coretid)648 static Thread* map_threads_maybe_lookup ( ThreadId coretid )
649 {
650 Thread* thr;
651 tl_assert( HG_(is_sane_ThreadId)(coretid) );
652 thr = map_threads[coretid];
653 return thr;
654 }
655
656 /* Asserts if the relevant map_threads entry is NULL. */
map_threads_lookup(ThreadId coretid)657 static inline Thread* map_threads_lookup ( ThreadId coretid )
658 {
659 Thread* thr;
660 tl_assert( HG_(is_sane_ThreadId)(coretid) );
661 thr = map_threads[coretid];
662 tl_assert(thr);
663 return thr;
664 }
665
666 /* Do a reverse lookup. Does not assert if 'thr' is not found in
667 map_threads. */
map_threads_maybe_reverse_lookup_SLOW(Thread * thr)668 static ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr )
669 {
670 ThreadId tid;
671 tl_assert(HG_(is_sane_Thread)(thr));
672 /* Check nobody used the invalid-threadid slot */
673 tl_assert(VG_INVALID_THREADID >= 0 && VG_INVALID_THREADID < VG_N_THREADS);
674 tl_assert(map_threads[VG_INVALID_THREADID] == NULL);
675 tid = thr->coretid;
676 tl_assert(HG_(is_sane_ThreadId)(tid));
677 return tid;
678 }
679
680 /* Do a reverse lookup. Warning: POTENTIALLY SLOW. Asserts if 'thr'
681 is not found in map_threads. */
map_threads_reverse_lookup_SLOW(Thread * thr)682 static ThreadId map_threads_reverse_lookup_SLOW ( Thread* thr )
683 {
684 ThreadId tid = map_threads_maybe_reverse_lookup_SLOW( thr );
685 tl_assert(tid != VG_INVALID_THREADID);
686 tl_assert(map_threads[tid]);
687 tl_assert(map_threads[tid]->coretid == tid);
688 return tid;
689 }
690
map_threads_delete(ThreadId coretid)691 static void map_threads_delete ( ThreadId coretid )
692 {
693 Thread* thr;
694 tl_assert(coretid != 0);
695 tl_assert( HG_(is_sane_ThreadId)(coretid) );
696 thr = map_threads[coretid];
697 tl_assert(thr);
698 map_threads[coretid] = NULL;
699 }
700
701
702 /*----------------------------------------------------------------*/
703 /*--- map_locks :: WordFM guest-Addr-of-lock Lock* ---*/
704 /*----------------------------------------------------------------*/
705
706 /* Make sure there is a lock table entry for the given (lock) guest
707 address. If not, create one of the stated 'kind' in unheld state.
708 In any case, return the address of the existing or new Lock. */
709 static
map_locks_lookup_or_create(LockKind lkk,Addr ga,ThreadId tid)710 Lock* map_locks_lookup_or_create ( LockKind lkk, Addr ga, ThreadId tid )
711 {
712 Bool found;
713 Lock* oldlock = NULL;
714 tl_assert(HG_(is_sane_ThreadId)(tid));
715 found = VG_(lookupFM)( map_locks,
716 NULL, (UWord*)&oldlock, (UWord)ga );
717 if (!found) {
718 Lock* lock = mk_LockN(lkk, ga);
719 lock->appeared_at = VG_(record_ExeContext)( tid, 0 );
720 tl_assert(HG_(is_sane_LockN)(lock));
721 VG_(addToFM)( map_locks, (UWord)ga, (UWord)lock );
722 tl_assert(oldlock == NULL);
723 return lock;
724 } else {
725 tl_assert(oldlock != NULL);
726 tl_assert(HG_(is_sane_LockN)(oldlock));
727 tl_assert(oldlock->guestaddr == ga);
728 return oldlock;
729 }
730 }
731
map_locks_maybe_lookup(Addr ga)732 static Lock* map_locks_maybe_lookup ( Addr ga )
733 {
734 Bool found;
735 Lock* lk = NULL;
736 found = VG_(lookupFM)( map_locks, NULL, (UWord*)&lk, (UWord)ga );
737 tl_assert(found ? lk != NULL : lk == NULL);
738 return lk;
739 }
740
map_locks_delete(Addr ga)741 static void map_locks_delete ( Addr ga )
742 {
743 Addr ga2 = 0;
744 Lock* lk = NULL;
745 VG_(delFromFM)( map_locks,
746 (UWord*)&ga2, (UWord*)&lk, (UWord)ga );
747 /* delFromFM produces the val which is being deleted, if it is
748 found. So assert it is non-null; that in effect asserts that we
749 are deleting a (ga, Lock) pair which actually exists. */
750 tl_assert(lk != NULL);
751 tl_assert(ga2 == ga);
752 }
753
754
755
756 /*----------------------------------------------------------------*/
757 /*--- Sanity checking the data structures ---*/
758 /*----------------------------------------------------------------*/
759
760 static UWord stats__sanity_checks = 0;
761
762 static void laog__sanity_check ( const HChar* who ); /* fwds */
763
764 /* REQUIRED INVARIANTS:
765
766 Thread vs Segment/Lock/SecMaps
767
768 for each t in Threads {
769
770 // Thread.lockset: each element is really a valid Lock
771
772 // Thread.lockset: each Lock in set is actually held by that thread
773 for lk in Thread.lockset
774 lk == LockedBy(t)
775
776 // Thread.csegid is a valid SegmentID
777 // and the associated Segment has .thr == t
778
779 }
780
781 all thread Locksets are pairwise empty under intersection
782 (that is, no lock is claimed to be held by more than one thread)
783 -- this is guaranteed if all locks in locksets point back to their
784 owner threads
785
786 Lock vs Thread/Segment/SecMaps
787
788 for each entry (gla, la) in map_locks
789 gla == la->guest_addr
790
791 for each lk in Locks {
792
793 lk->tag is valid
794 lk->guest_addr does not have shadow state NoAccess
795 if lk == LockedBy(t), then t->lockset contains lk
796 if lk == UnlockedBy(segid) then segid is valid SegmentID
797 and can be mapped to a valid Segment(seg)
798 and seg->thr->lockset does not contain lk
799 if lk == UnlockedNew then (no lockset contains lk)
800
801 secmaps for lk has .mbHasLocks == True
802
803 }
804
805 Segment vs Thread/Lock/SecMaps
806
807 the Segment graph is a dag (no cycles)
808 all of the Segment graph must be reachable from the segids
809 mentioned in the Threads
810
811 for seg in Segments {
812
813 seg->thr is a sane Thread
814
815 }
816
817 SecMaps vs Segment/Thread/Lock
818
819 for sm in SecMaps {
820
821 sm properly aligned
822 if any shadow word is ShR or ShM then .mbHasShared == True
823
824 for each Excl(segid) state
825 map_segments_lookup maps to a sane Segment(seg)
826 for each ShM/ShR(tsetid,lsetid) state
827 each lk in lset is a valid Lock
828 each thr in tset is a valid thread, which is non-dead
829
830 }
831 */
832
833
834 /* Return True iff 'thr' holds 'lk' in some mode. */
thread_is_a_holder_of_Lock(Thread * thr,Lock * lk)835 static Bool thread_is_a_holder_of_Lock ( Thread* thr, Lock* lk )
836 {
837 if (lk->heldBy)
838 return VG_(elemBag)( lk->heldBy, (UWord)thr ) > 0;
839 else
840 return False;
841 }
842
843 /* Sanity check Threads, as far as possible */
844 __attribute__((noinline))
threads__sanity_check(const HChar * who)845 static void threads__sanity_check ( const HChar* who )
846 {
847 #define BAD(_str) do { how = (_str); goto bad; } while (0)
848 const HChar* how = "no error";
849 Thread* thr;
850 WordSetID wsA, wsW;
851 UWord* ls_words;
852 UWord ls_size, i;
853 Lock* lk;
854 for (thr = admin_threads; thr; thr = thr->admin) {
855 if (!HG_(is_sane_Thread)(thr)) BAD("1");
856 wsA = thr->locksetA;
857 wsW = thr->locksetW;
858 // locks held in W mode are a subset of all locks held
859 if (!HG_(isSubsetOf)( univ_lsets, wsW, wsA )) BAD("7");
860 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, wsA );
861 for (i = 0; i < ls_size; i++) {
862 lk = (Lock*)ls_words[i];
863 // Thread.lockset: each element is really a valid Lock
864 if (!HG_(is_sane_LockN)(lk)) BAD("2");
865 // Thread.lockset: each Lock in set is actually held by that
866 // thread
867 if (!thread_is_a_holder_of_Lock(thr,lk)) BAD("3");
868 }
869 }
870 return;
871 bad:
872 VG_(printf)("threads__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
873 tl_assert(0);
874 #undef BAD
875 }
876
877
878 /* Sanity check Locks, as far as possible */
879 __attribute__((noinline))
locks__sanity_check(const HChar * who)880 static void locks__sanity_check ( const HChar* who )
881 {
882 #define BAD(_str) do { how = (_str); goto bad; } while (0)
883 const HChar* how = "no error";
884 Addr gla;
885 Lock* lk;
886 Int i;
887 // # entries in admin_locks == # entries in map_locks
888 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next)
889 ;
890 if (i != VG_(sizeFM)(map_locks)) BAD("1");
891 // for each entry (gla, lk) in map_locks
892 // gla == lk->guest_addr
893 VG_(initIterFM)( map_locks );
894 while (VG_(nextIterFM)( map_locks,
895 (UWord*)&gla, (UWord*)&lk )) {
896 if (lk->guestaddr != gla) BAD("2");
897 }
898 VG_(doneIterFM)( map_locks );
899 // scan through admin_locks ...
900 for (lk = admin_locks; lk; lk = lk->admin_next) {
901 // lock is sane. Quite comprehensive, also checks that
902 // referenced (holder) threads are sane.
903 if (!HG_(is_sane_LockN)(lk)) BAD("3");
904 // map_locks binds guest address back to this lock
905 if (lk != map_locks_maybe_lookup(lk->guestaddr)) BAD("4");
906 // look at all threads mentioned as holders of this lock. Ensure
907 // this lock is mentioned in their locksets.
908 if (lk->heldBy) {
909 Thread* thr;
910 UWord count;
911 VG_(initIterBag)( lk->heldBy );
912 while (VG_(nextIterBag)( lk->heldBy,
913 (UWord*)&thr, &count )) {
914 // HG_(is_sane_LockN) above ensures these
915 tl_assert(count >= 1);
916 tl_assert(HG_(is_sane_Thread)(thr));
917 if (!HG_(elemWS)(univ_lsets, thr->locksetA, (UWord)lk))
918 BAD("6");
919 // also check the w-only lockset
920 if (lk->heldW
921 && !HG_(elemWS)(univ_lsets, thr->locksetW, (UWord)lk))
922 BAD("7");
923 if ((!lk->heldW)
924 && HG_(elemWS)(univ_lsets, thr->locksetW, (UWord)lk))
925 BAD("8");
926 }
927 VG_(doneIterBag)( lk->heldBy );
928 } else {
929 /* lock not held by anybody */
930 if (lk->heldW) BAD("9"); /* should be False if !heldBy */
931 // since lk is unheld, then (no lockset contains lk)
932 // hmm, this is really too expensive to check. Hmm.
933 }
934 }
935
936 return;
937 bad:
938 VG_(printf)("locks__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
939 tl_assert(0);
940 #undef BAD
941 }
942
943
all_except_Locks__sanity_check(const HChar * who)944 static void all_except_Locks__sanity_check ( const HChar* who ) {
945 stats__sanity_checks++;
946 if (0) VG_(printf)("all_except_Locks__sanity_check(%s)\n", who);
947 threads__sanity_check(who);
948 if (HG_(clo_track_lockorders))
949 laog__sanity_check(who);
950 }
all__sanity_check(const HChar * who)951 static void all__sanity_check ( const HChar* who ) {
952 all_except_Locks__sanity_check(who);
953 locks__sanity_check(who);
954 }
955
956
957 /*----------------------------------------------------------------*/
958 /*--- Shadow value and address range handlers ---*/
959 /*----------------------------------------------------------------*/
960
961 static void laog__pre_thread_acquires_lock ( Thread*, Lock* ); /* fwds */
962 //static void laog__handle_lock_deletions ( WordSetID ); /* fwds */
963 static inline Thread* get_current_Thread ( void ); /* fwds */
964 __attribute__((noinline))
965 static void laog__handle_one_lock_deletion ( Lock* lk ); /* fwds */
966
967
968 /* Block-copy states (needed for implementing realloc()). */
969 /* FIXME this copies shadow memory; it doesn't apply the MSM to it.
970 Is that a problem? (hence 'scopy' rather than 'ccopy') */
shadow_mem_scopy_range(Thread * thr,Addr src,Addr dst,SizeT len)971 static void shadow_mem_scopy_range ( Thread* thr,
972 Addr src, Addr dst, SizeT len )
973 {
974 Thr* hbthr = thr->hbthr;
975 tl_assert(hbthr);
976 libhb_copy_shadow_state( hbthr, src, dst, len );
977 }
978
shadow_mem_cread_range(Thread * thr,Addr a,SizeT len)979 static void shadow_mem_cread_range ( Thread* thr, Addr a, SizeT len )
980 {
981 Thr* hbthr = thr->hbthr;
982 tl_assert(hbthr);
983 LIBHB_CREAD_N(hbthr, a, len);
984 }
985
shadow_mem_cwrite_range(Thread * thr,Addr a,SizeT len)986 static void shadow_mem_cwrite_range ( Thread* thr, Addr a, SizeT len ) {
987 Thr* hbthr = thr->hbthr;
988 tl_assert(hbthr);
989 LIBHB_CWRITE_N(hbthr, a, len);
990 }
991
shadow_mem_make_New(Thread * thr,Addr a,SizeT len)992 static void shadow_mem_make_New ( Thread* thr, Addr a, SizeT len )
993 {
994 libhb_srange_new( thr->hbthr, a, len );
995 }
996
shadow_mem_make_NoAccess_NoFX(Thread * thr,Addr aIN,SizeT len)997 static void shadow_mem_make_NoAccess_NoFX ( Thread* thr, Addr aIN, SizeT len )
998 {
999 if (0 && len > 500)
1000 VG_(printf)("make NoAccess_NoFX ( %#lx, %ld )\n", aIN, len );
1001 // has no effect (NoFX)
1002 libhb_srange_noaccess_NoFX( thr->hbthr, aIN, len );
1003 }
1004
shadow_mem_make_NoAccess_AHAE(Thread * thr,Addr aIN,SizeT len)1005 static void shadow_mem_make_NoAccess_AHAE ( Thread* thr, Addr aIN, SizeT len )
1006 {
1007 if (0 && len > 500)
1008 VG_(printf)("make NoAccess_AHAE ( %#lx, %ld )\n", aIN, len );
1009 // Actually Has An Effect (AHAE)
1010 libhb_srange_noaccess_AHAE( thr->hbthr, aIN, len );
1011 }
1012
shadow_mem_make_Untracked(Thread * thr,Addr aIN,SizeT len)1013 static void shadow_mem_make_Untracked ( Thread* thr, Addr aIN, SizeT len )
1014 {
1015 if (0 && len > 500)
1016 VG_(printf)("make Untracked ( %#lx, %ld )\n", aIN, len );
1017 libhb_srange_untrack( thr->hbthr, aIN, len );
1018 }
1019
1020
1021 /*----------------------------------------------------------------*/
1022 /*--- Event handlers (evh__* functions) ---*/
1023 /*--- plus helpers (evhH__* functions) ---*/
1024 /*----------------------------------------------------------------*/
1025
1026 /*--------- Event handler helpers (evhH__* functions) ---------*/
1027
1028 /* Create a new segment for 'thr', making it depend (.prev) on its
1029 existing segment, bind together the SegmentID and Segment, and
1030 return both of them. Also update 'thr' so it references the new
1031 Segment. */
1032 //zz static
1033 //zz void evhH__start_new_segment_for_thread ( /*OUT*/SegmentID* new_segidP,
1034 //zz /*OUT*/Segment** new_segP,
1035 //zz Thread* thr )
1036 //zz {
1037 //zz Segment* cur_seg;
1038 //zz tl_assert(new_segP);
1039 //zz tl_assert(new_segidP);
1040 //zz tl_assert(HG_(is_sane_Thread)(thr));
1041 //zz cur_seg = map_segments_lookup( thr->csegid );
1042 //zz tl_assert(cur_seg);
1043 //zz tl_assert(cur_seg->thr == thr); /* all sane segs should point back
1044 //zz at their owner thread. */
1045 //zz *new_segP = mk_Segment( thr, cur_seg, NULL/*other*/ );
1046 //zz *new_segidP = alloc_SegmentID();
1047 //zz map_segments_add( *new_segidP, *new_segP );
1048 //zz thr->csegid = *new_segidP;
1049 //zz }
1050
1051
1052 /* The lock at 'lock_ga' has acquired a writer. Make all necessary
1053 updates, and also do all possible error checks. */
1054 static
evhH__post_thread_w_acquires_lock(Thread * thr,LockKind lkk,Addr lock_ga)1055 void evhH__post_thread_w_acquires_lock ( Thread* thr,
1056 LockKind lkk, Addr lock_ga )
1057 {
1058 Lock* lk;
1059
1060 /* Basically what we need to do is call lockN_acquire_writer.
1061 However, that will barf if any 'invalid' lock states would
1062 result. Therefore check before calling. Side effect is that
1063 'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
1064 routine.
1065
1066 Because this routine is only called after successful lock
1067 acquisition, we should not be asked to move the lock into any
1068 invalid states. Requests to do so are bugs in libpthread, since
1069 that should have rejected any such requests. */
1070
1071 tl_assert(HG_(is_sane_Thread)(thr));
1072 /* Try to find the lock. If we can't, then create a new one with
1073 kind 'lkk'. */
1074 lk = map_locks_lookup_or_create(
1075 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
1076 tl_assert( HG_(is_sane_LockN)(lk) );
1077
1078 /* check libhb level entities exist */
1079 tl_assert(thr->hbthr);
1080 tl_assert(lk->hbso);
1081
1082 if (lk->heldBy == NULL) {
1083 /* the lock isn't held. Simple. */
1084 tl_assert(!lk->heldW);
1085 lockN_acquire_writer( lk, thr );
1086 /* acquire a dependency from the lock's VCs */
1087 libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
1088 goto noerror;
1089 }
1090
1091 /* So the lock is already held. If held as a r-lock then
1092 libpthread must be buggy. */
1093 tl_assert(lk->heldBy);
1094 if (!lk->heldW) {
1095 HG_(record_error_Misc)(
1096 thr, "Bug in libpthread: write lock "
1097 "granted on rwlock which is currently rd-held");
1098 goto error;
1099 }
1100
1101 /* So the lock is held in w-mode. If it's held by some other
1102 thread, then libpthread must be buggy. */
1103 tl_assert(VG_(sizeUniqueBag)(lk->heldBy) == 1); /* from precondition */
1104
1105 if (thr != (Thread*)VG_(anyElementOfBag)(lk->heldBy)) {
1106 HG_(record_error_Misc)(
1107 thr, "Bug in libpthread: write lock "
1108 "granted on mutex/rwlock which is currently "
1109 "wr-held by a different thread");
1110 goto error;
1111 }
1112
1113 /* So the lock is already held in w-mode by 'thr'. That means this
1114 is an attempt to lock it recursively, which is only allowable
1115 for LK_mbRec kinded locks. Since this routine is called only
1116 once the lock has been acquired, this must also be a libpthread
1117 bug. */
1118 if (lk->kind != LK_mbRec) {
1119 HG_(record_error_Misc)(
1120 thr, "Bug in libpthread: recursive write lock "
1121 "granted on mutex/wrlock which does not "
1122 "support recursion");
1123 goto error;
1124 }
1125
1126 /* So we are recursively re-locking a lock we already w-hold. */
1127 lockN_acquire_writer( lk, thr );
1128 /* acquire a dependency from the lock's VC. Probably pointless,
1129 but also harmless. */
1130 libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
1131 goto noerror;
1132
1133 noerror:
1134 if (HG_(clo_track_lockorders)) {
1135 /* check lock order acquisition graph, and update. This has to
1136 happen before the lock is added to the thread's locksetA/W. */
1137 laog__pre_thread_acquires_lock( thr, lk );
1138 }
1139 /* update the thread's held-locks set */
1140 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (UWord)lk );
1141 thr->locksetW = HG_(addToWS)( univ_lsets, thr->locksetW, (UWord)lk );
1142 /* fall through */
1143
1144 error:
1145 tl_assert(HG_(is_sane_LockN)(lk));
1146 }
1147
1148
1149 /* The lock at 'lock_ga' has acquired a reader. Make all necessary
1150 updates, and also do all possible error checks. */
1151 static
evhH__post_thread_r_acquires_lock(Thread * thr,LockKind lkk,Addr lock_ga)1152 void evhH__post_thread_r_acquires_lock ( Thread* thr,
1153 LockKind lkk, Addr lock_ga )
1154 {
1155 Lock* lk;
1156
1157 /* Basically what we need to do is call lockN_acquire_reader.
1158 However, that will barf if any 'invalid' lock states would
1159 result. Therefore check before calling. Side effect is that
1160 'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
1161 routine.
1162
1163 Because this routine is only called after successful lock
1164 acquisition, we should not be asked to move the lock into any
1165 invalid states. Requests to do so are bugs in libpthread, since
1166 that should have rejected any such requests. */
1167
1168 tl_assert(HG_(is_sane_Thread)(thr));
1169 /* Try to find the lock. If we can't, then create a new one with
1170 kind 'lkk'. Only a reader-writer lock can be read-locked,
1171 hence the first assertion. */
1172 tl_assert(lkk == LK_rdwr);
1173 lk = map_locks_lookup_or_create(
1174 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
1175 tl_assert( HG_(is_sane_LockN)(lk) );
1176
1177 /* check libhb level entities exist */
1178 tl_assert(thr->hbthr);
1179 tl_assert(lk->hbso);
1180
1181 if (lk->heldBy == NULL) {
1182 /* the lock isn't held. Simple. */
1183 tl_assert(!lk->heldW);
1184 lockN_acquire_reader( lk, thr );
1185 /* acquire a dependency from the lock's VC */
1186 libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
1187 goto noerror;
1188 }
1189
1190 /* So the lock is already held. If held as a w-lock then
1191 libpthread must be buggy. */
1192 tl_assert(lk->heldBy);
1193 if (lk->heldW) {
1194 HG_(record_error_Misc)( thr, "Bug in libpthread: read lock "
1195 "granted on rwlock which is "
1196 "currently wr-held");
1197 goto error;
1198 }
1199
1200 /* Easy enough. In short anybody can get a read-lock on a rwlock
1201 provided it is either unlocked or already in rd-held. */
1202 lockN_acquire_reader( lk, thr );
1203 /* acquire a dependency from the lock's VC. Probably pointless,
1204 but also harmless. */
1205 libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
1206 goto noerror;
1207
1208 noerror:
1209 if (HG_(clo_track_lockorders)) {
1210 /* check lock order acquisition graph, and update. This has to
1211 happen before the lock is added to the thread's locksetA/W. */
1212 laog__pre_thread_acquires_lock( thr, lk );
1213 }
1214 /* update the thread's held-locks set */
1215 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (UWord)lk );
1216 /* but don't update thr->locksetW, since lk is only rd-held */
1217 /* fall through */
1218
1219 error:
1220 tl_assert(HG_(is_sane_LockN)(lk));
1221 }
1222
1223
1224 /* The lock at 'lock_ga' is just about to be unlocked. Make all
1225 necessary updates, and also do all possible error checks. */
1226 static
evhH__pre_thread_releases_lock(Thread * thr,Addr lock_ga,Bool isRDWR)1227 void evhH__pre_thread_releases_lock ( Thread* thr,
1228 Addr lock_ga, Bool isRDWR )
1229 {
1230 Lock* lock;
1231 Word n;
1232 Bool was_heldW;
1233
1234 /* This routine is called prior to a lock release, before
1235 libpthread has had a chance to validate the call. Hence we need
1236 to detect and reject any attempts to move the lock into an
1237 invalid state. Such attempts are bugs in the client.
1238
1239 isRDWR is True if we know from the wrapper context that lock_ga
1240 should refer to a reader-writer lock, and is False if [ditto]
1241 lock_ga should refer to a standard mutex. */
1242
1243 tl_assert(HG_(is_sane_Thread)(thr));
1244 lock = map_locks_maybe_lookup( lock_ga );
1245
1246 if (!lock) {
1247 /* We know nothing about a lock at 'lock_ga'. Nevertheless
1248 the client is trying to unlock it. So complain, then ignore
1249 the attempt. */
1250 HG_(record_error_UnlockBogus)( thr, lock_ga );
1251 return;
1252 }
1253
1254 tl_assert(lock->guestaddr == lock_ga);
1255 tl_assert(HG_(is_sane_LockN)(lock));
1256
1257 if (isRDWR && lock->kind != LK_rdwr) {
1258 HG_(record_error_Misc)( thr, "pthread_rwlock_unlock with a "
1259 "pthread_mutex_t* argument " );
1260 }
1261 if ((!isRDWR) && lock->kind == LK_rdwr) {
1262 HG_(record_error_Misc)( thr, "pthread_mutex_unlock with a "
1263 "pthread_rwlock_t* argument " );
1264 }
1265
1266 if (!lock->heldBy) {
1267 /* The lock is not held. This indicates a serious bug in the
1268 client. */
1269 tl_assert(!lock->heldW);
1270 HG_(record_error_UnlockUnlocked)( thr, lock );
1271 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lock ));
1272 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
1273 goto error;
1274 }
1275
1276 /* test just above dominates */
1277 tl_assert(lock->heldBy);
1278 was_heldW = lock->heldW;
1279
1280 /* The lock is held. Is this thread one of the holders? If not,
1281 report a bug in the client. */
1282 n = VG_(elemBag)( lock->heldBy, (UWord)thr );
1283 tl_assert(n >= 0);
1284 if (n == 0) {
1285 /* We are not a current holder of the lock. This is a bug in
1286 the guest, and (per POSIX pthread rules) the unlock
1287 attempt will fail. So just complain and do nothing
1288 else. */
1289 Thread* realOwner = (Thread*)VG_(anyElementOfBag)( lock->heldBy );
1290 tl_assert(HG_(is_sane_Thread)(realOwner));
1291 tl_assert(realOwner != thr);
1292 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lock ));
1293 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
1294 HG_(record_error_UnlockForeign)( thr, realOwner, lock );
1295 goto error;
1296 }
1297
1298 /* Ok, we hold the lock 'n' times. */
1299 tl_assert(n >= 1);
1300
1301 lockN_release( lock, thr );
1302
1303 n--;
1304 tl_assert(n >= 0);
1305
1306 if (n > 0) {
1307 tl_assert(lock->heldBy);
1308 tl_assert(n == VG_(elemBag)( lock->heldBy, (UWord)thr ));
1309 /* We still hold the lock. So either it's a recursive lock
1310 or a rwlock which is currently r-held. */
1311 tl_assert(lock->kind == LK_mbRec
1312 || (lock->kind == LK_rdwr && !lock->heldW));
1313 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lock ));
1314 if (lock->heldW)
1315 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
1316 else
1317 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
1318 } else {
1319 /* n is zero. This means we don't hold the lock any more. But
1320 if it's a rwlock held in r-mode, someone else could still
1321 hold it. Just do whatever sanity checks we can. */
1322 if (lock->kind == LK_rdwr && lock->heldBy) {
1323 /* It's a rwlock. We no longer hold it but we used to;
1324 nevertheless it still appears to be held by someone else.
1325 The implication is that, prior to this release, it must
1326 have been shared by us and and whoever else is holding it;
1327 which in turn implies it must be r-held, since a lock
1328 can't be w-held by more than one thread. */
1329 /* The lock is now R-held by somebody else: */
1330 tl_assert(lock->heldW == False);
1331 } else {
1332 /* Normal case. It's either not a rwlock, or it's a rwlock
1333 that we used to hold in w-mode (which is pretty much the
1334 same thing as a non-rwlock.) Since this transaction is
1335 atomic (V does not allow multiple threads to run
1336 simultaneously), it must mean the lock is now not held by
1337 anybody. Hence assert for it. */
1338 /* The lock is now not held by anybody: */
1339 tl_assert(!lock->heldBy);
1340 tl_assert(lock->heldW == False);
1341 }
1342 //if (lock->heldBy) {
1343 // tl_assert(0 == VG_(elemBag)( lock->heldBy, (UWord)thr ));
1344 //}
1345 /* update this thread's lockset accordingly. */
1346 thr->locksetA
1347 = HG_(delFromWS)( univ_lsets, thr->locksetA, (UWord)lock );
1348 thr->locksetW
1349 = HG_(delFromWS)( univ_lsets, thr->locksetW, (UWord)lock );
1350 /* push our VC into the lock */
1351 tl_assert(thr->hbthr);
1352 tl_assert(lock->hbso);
1353 /* If the lock was previously W-held, then we want to do a
1354 strong send, and if previously R-held, then a weak send. */
1355 libhb_so_send( thr->hbthr, lock->hbso, was_heldW );
1356 }
1357 /* fall through */
1358
1359 error:
1360 tl_assert(HG_(is_sane_LockN)(lock));
1361 }
1362
1363
1364 /* ---------------------------------------------------------- */
1365 /* -------- Event handlers proper (evh__* functions) -------- */
1366 /* ---------------------------------------------------------- */
1367
1368 /* What is the Thread* for the currently running thread? This is
1369 absolutely performance critical. We receive notifications from the
1370 core for client code starts/stops, and cache the looked-up result
1371 in 'current_Thread'. Hence, for the vast majority of requests,
1372 finding the current thread reduces to a read of a global variable,
1373 provided get_current_Thread_in_C_C is inlined.
1374
1375 Outside of client code, current_Thread is NULL, and presumably
1376 any uses of it will cause a segfault. Hence:
1377
1378 - for uses definitely within client code, use
1379 get_current_Thread_in_C_C.
1380
1381 - for all other uses, use get_current_Thread.
1382 */
1383
1384 static Thread *current_Thread = NULL,
1385 *current_Thread_prev = NULL;
1386
evh__start_client_code(ThreadId tid,ULong nDisp)1387 static void evh__start_client_code ( ThreadId tid, ULong nDisp ) {
1388 if (0) VG_(printf)("start %d %llu\n", (Int)tid, nDisp);
1389 tl_assert(current_Thread == NULL);
1390 current_Thread = map_threads_lookup( tid );
1391 tl_assert(current_Thread != NULL);
1392 if (current_Thread != current_Thread_prev) {
1393 libhb_Thr_resumes( current_Thread->hbthr );
1394 current_Thread_prev = current_Thread;
1395 }
1396 }
evh__stop_client_code(ThreadId tid,ULong nDisp)1397 static void evh__stop_client_code ( ThreadId tid, ULong nDisp ) {
1398 if (0) VG_(printf)(" stop %d %llu\n", (Int)tid, nDisp);
1399 tl_assert(current_Thread != NULL);
1400 current_Thread = NULL;
1401 libhb_maybe_GC();
1402 }
get_current_Thread_in_C_C(void)1403 static inline Thread* get_current_Thread_in_C_C ( void ) {
1404 return current_Thread;
1405 }
get_current_Thread(void)1406 static inline Thread* get_current_Thread ( void ) {
1407 ThreadId coretid;
1408 Thread* thr;
1409 thr = get_current_Thread_in_C_C();
1410 if (LIKELY(thr))
1411 return thr;
1412 /* evidently not in client code. Do it the slow way. */
1413 coretid = VG_(get_running_tid)();
1414 /* FIXME: get rid of the following kludge. It exists because
1415 evh__new_mem is called during initialisation (as notification
1416 of initial memory layout) and VG_(get_running_tid)() returns
1417 VG_INVALID_THREADID at that point. */
1418 if (coretid == VG_INVALID_THREADID)
1419 coretid = 1; /* KLUDGE */
1420 thr = map_threads_lookup( coretid );
1421 return thr;
1422 }
1423
1424 static
evh__new_mem(Addr a,SizeT len)1425 void evh__new_mem ( Addr a, SizeT len ) {
1426 if (SHOW_EVENTS >= 2)
1427 VG_(printf)("evh__new_mem(%p, %lu)\n", (void*)a, len );
1428 shadow_mem_make_New( get_current_Thread(), a, len );
1429 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1430 all__sanity_check("evh__new_mem-post");
1431 }
1432
1433 static
evh__new_mem_stack(Addr a,SizeT len)1434 void evh__new_mem_stack ( Addr a, SizeT len ) {
1435 if (SHOW_EVENTS >= 2)
1436 VG_(printf)("evh__new_mem_stack(%p, %lu)\n", (void*)a, len );
1437 shadow_mem_make_New( get_current_Thread(),
1438 -VG_STACK_REDZONE_SZB + a, len );
1439 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1440 all__sanity_check("evh__new_mem_stack-post");
1441 }
1442
1443 static
evh__new_mem_w_tid(Addr a,SizeT len,ThreadId tid)1444 void evh__new_mem_w_tid ( Addr a, SizeT len, ThreadId tid ) {
1445 if (SHOW_EVENTS >= 2)
1446 VG_(printf)("evh__new_mem_w_tid(%p, %lu)\n", (void*)a, len );
1447 shadow_mem_make_New( get_current_Thread(), a, len );
1448 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1449 all__sanity_check("evh__new_mem_w_tid-post");
1450 }
1451
1452 static
evh__new_mem_w_perms(Addr a,SizeT len,Bool rr,Bool ww,Bool xx,ULong di_handle)1453 void evh__new_mem_w_perms ( Addr a, SizeT len,
1454 Bool rr, Bool ww, Bool xx, ULong di_handle ) {
1455 if (SHOW_EVENTS >= 1)
1456 VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
1457 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1458 if (rr || ww || xx)
1459 shadow_mem_make_New( get_current_Thread(), a, len );
1460 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1461 all__sanity_check("evh__new_mem_w_perms-post");
1462 }
1463
1464 static
evh__set_perms(Addr a,SizeT len,Bool rr,Bool ww,Bool xx)1465 void evh__set_perms ( Addr a, SizeT len,
1466 Bool rr, Bool ww, Bool xx ) {
1467 // This handles mprotect requests. If the memory is being put
1468 // into no-R no-W state, paint it as NoAccess, for the reasons
1469 // documented at evh__die_mem_munmap().
1470 if (SHOW_EVENTS >= 1)
1471 VG_(printf)("evh__set_perms(%p, %lu, r=%d w=%d x=%d)\n",
1472 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1473 /* Hmm. What should we do here, that actually makes any sense?
1474 Let's say: if neither readable nor writable, then declare it
1475 NoAccess, else leave it alone. */
1476 if (!(rr || ww))
1477 shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
1478 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1479 all__sanity_check("evh__set_perms-post");
1480 }
1481
1482 static
evh__die_mem(Addr a,SizeT len)1483 void evh__die_mem ( Addr a, SizeT len ) {
1484 // Urr, libhb ignores this.
1485 if (SHOW_EVENTS >= 2)
1486 VG_(printf)("evh__die_mem(%p, %lu)\n", (void*)a, len );
1487 shadow_mem_make_NoAccess_NoFX( get_current_Thread(), a, len );
1488 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1489 all__sanity_check("evh__die_mem-post");
1490 }
1491
1492 static
evh__die_mem_munmap(Addr a,SizeT len)1493 void evh__die_mem_munmap ( Addr a, SizeT len ) {
1494 // It's important that libhb doesn't ignore this. If, as is likely,
1495 // the client is subject to address space layout randomization,
1496 // then unmapped areas may never get remapped over, even in long
1497 // runs. If we just ignore them we wind up with large resource
1498 // (VTS) leaks in libhb. So force them to NoAccess, so that all
1499 // VTS references in the affected area are dropped. Marking memory
1500 // as NoAccess is expensive, but we assume that munmap is sufficiently
1501 // rare that the space gains of doing this are worth the costs.
1502 if (SHOW_EVENTS >= 2)
1503 VG_(printf)("evh__die_mem_munmap(%p, %lu)\n", (void*)a, len );
1504 shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
1505 }
1506
1507 static
evh__untrack_mem(Addr a,SizeT len)1508 void evh__untrack_mem ( Addr a, SizeT len ) {
1509 // Libhb doesn't ignore this.
1510 if (SHOW_EVENTS >= 2)
1511 VG_(printf)("evh__untrack_mem(%p, %lu)\n", (void*)a, len );
1512 shadow_mem_make_Untracked( get_current_Thread(), a, len );
1513 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1514 all__sanity_check("evh__untrack_mem-post");
1515 }
1516
1517 static
evh__copy_mem(Addr src,Addr dst,SizeT len)1518 void evh__copy_mem ( Addr src, Addr dst, SizeT len ) {
1519 if (SHOW_EVENTS >= 2)
1520 VG_(printf)("evh__copy_mem(%p, %p, %lu)\n", (void*)src, (void*)dst, len );
1521 shadow_mem_scopy_range( get_current_Thread(), src, dst, len );
1522 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1523 all__sanity_check("evh__copy_mem-post");
1524 }
1525
1526 static
evh__pre_thread_ll_create(ThreadId parent,ThreadId child)1527 void evh__pre_thread_ll_create ( ThreadId parent, ThreadId child )
1528 {
1529 if (SHOW_EVENTS >= 1)
1530 VG_(printf)("evh__pre_thread_ll_create(p=%d, c=%d)\n",
1531 (Int)parent, (Int)child );
1532
1533 if (parent != VG_INVALID_THREADID) {
1534 Thread* thr_p;
1535 Thread* thr_c;
1536 Thr* hbthr_p;
1537 Thr* hbthr_c;
1538
1539 tl_assert(HG_(is_sane_ThreadId)(parent));
1540 tl_assert(HG_(is_sane_ThreadId)(child));
1541 tl_assert(parent != child);
1542
1543 thr_p = map_threads_maybe_lookup( parent );
1544 thr_c = map_threads_maybe_lookup( child );
1545
1546 tl_assert(thr_p != NULL);
1547 tl_assert(thr_c == NULL);
1548
1549 hbthr_p = thr_p->hbthr;
1550 tl_assert(hbthr_p != NULL);
1551 tl_assert( libhb_get_Thr_hgthread(hbthr_p) == thr_p );
1552
1553 hbthr_c = libhb_create ( hbthr_p );
1554
1555 /* Create a new thread record for the child. */
1556 /* a Thread for the new thread ... */
1557 thr_c = mk_Thread( hbthr_c );
1558 tl_assert( libhb_get_Thr_hgthread(hbthr_c) == NULL );
1559 libhb_set_Thr_hgthread(hbthr_c, thr_c);
1560
1561 /* and bind it in the thread-map table */
1562 map_threads[child] = thr_c;
1563 tl_assert(thr_c->coretid == VG_INVALID_THREADID);
1564 thr_c->coretid = child;
1565
1566 /* Record where the parent is so we can later refer to this in
1567 error messages.
1568
1569 On x86/amd64-linux, this entails a nasty glibc specific hack.
1570 The stack snapshot is taken immediately after the parent has
1571 returned from its sys_clone call. Unfortunately there is no
1572 unwind info for the insn following "syscall" - reading the
1573 glibc sources confirms this. So we ask for a snapshot to be
1574 taken as if RIP was 3 bytes earlier, in a place where there
1575 is unwind info. Sigh.
1576 */
1577 { Word first_ip_delta = 0;
1578 # if defined(VGP_amd64_linux) || defined(VGP_x86_linux)
1579 first_ip_delta = -3;
1580 # elif defined(VGP_arm64_linux) || defined(VGP_arm_linux)
1581 first_ip_delta = -1;
1582 # endif
1583 thr_c->created_at = VG_(record_ExeContext)(parent, first_ip_delta);
1584 }
1585 }
1586
1587 if (HG_(clo_sanity_flags) & SCE_THREADS)
1588 all__sanity_check("evh__pre_thread_create-post");
1589 }
1590
1591 static
evh__pre_thread_ll_exit(ThreadId quit_tid)1592 void evh__pre_thread_ll_exit ( ThreadId quit_tid )
1593 {
1594 Int nHeld;
1595 Thread* thr_q;
1596 if (SHOW_EVENTS >= 1)
1597 VG_(printf)("evh__pre_thread_ll_exit(thr=%d)\n",
1598 (Int)quit_tid );
1599
1600 /* quit_tid has disappeared without joining to any other thread.
1601 Therefore there is no synchronisation event associated with its
1602 exit and so we have to pretty much treat it as if it was still
1603 alive but mysteriously making no progress. That is because, if
1604 we don't know when it really exited, then we can never say there
1605 is a point in time when we're sure the thread really has
1606 finished, and so we need to consider the possibility that it
1607 lingers indefinitely and continues to interact with other
1608 threads. */
1609 /* However, it might have rendezvous'd with a thread that called
1610 pthread_join with this one as arg, prior to this point (that's
1611 how NPTL works). In which case there has already been a prior
1612 sync event. So in any case, just let the thread exit. On NPTL,
1613 all thread exits go through here. */
1614 tl_assert(HG_(is_sane_ThreadId)(quit_tid));
1615 thr_q = map_threads_maybe_lookup( quit_tid );
1616 tl_assert(thr_q != NULL);
1617
1618 /* Complain if this thread holds any locks. */
1619 nHeld = HG_(cardinalityWS)( univ_lsets, thr_q->locksetA );
1620 tl_assert(nHeld >= 0);
1621 if (nHeld > 0) {
1622 HChar buf[80];
1623 VG_(sprintf)(buf, "Exiting thread still holds %d lock%s",
1624 nHeld, nHeld > 1 ? "s" : "");
1625 HG_(record_error_Misc)( thr_q, buf );
1626 }
1627
1628 /* Not much to do here:
1629 - tell libhb the thread is gone
1630 - clear the map_threads entry, in order that the Valgrind core
1631 can re-use it. */
1632 /* Cleanup actions (next 5 lines) copied in evh__atfork_child; keep
1633 in sync. */
1634 tl_assert(thr_q->hbthr);
1635 libhb_async_exit(thr_q->hbthr);
1636 tl_assert(thr_q->coretid == quit_tid);
1637 thr_q->coretid = VG_INVALID_THREADID;
1638 map_threads_delete( quit_tid );
1639
1640 if (HG_(clo_sanity_flags) & SCE_THREADS)
1641 all__sanity_check("evh__pre_thread_ll_exit-post");
1642 }
1643
1644 /* This is called immediately after fork, for the child only. 'tid'
1645 is the only surviving thread (as per POSIX rules on fork() in
1646 threaded programs), so we have to clean up map_threads to remove
1647 entries for any other threads. */
1648 static
evh__atfork_child(ThreadId tid)1649 void evh__atfork_child ( ThreadId tid )
1650 {
1651 UInt i;
1652 Thread* thr;
1653 /* Slot 0 should never be used. */
1654 thr = map_threads_maybe_lookup( 0/*INVALID*/ );
1655 tl_assert(!thr);
1656 /* Clean up all other slots except 'tid'. */
1657 for (i = 1; i < VG_N_THREADS; i++) {
1658 if (i == tid)
1659 continue;
1660 thr = map_threads_maybe_lookup(i);
1661 if (!thr)
1662 continue;
1663 /* Cleanup actions (next 5 lines) copied from end of
1664 evh__pre_thread_ll_exit; keep in sync. */
1665 tl_assert(thr->hbthr);
1666 libhb_async_exit(thr->hbthr);
1667 tl_assert(thr->coretid == i);
1668 thr->coretid = VG_INVALID_THREADID;
1669 map_threads_delete(i);
1670 }
1671 }
1672
1673 /* generate a dependence from the hbthr_q quitter to the hbthr_s stayer. */
1674 static
generate_quitter_stayer_dependence(Thr * hbthr_q,Thr * hbthr_s)1675 void generate_quitter_stayer_dependence (Thr* hbthr_q, Thr* hbthr_s)
1676 {
1677 SO* so;
1678 /* Allocate a temporary synchronisation object and use it to send
1679 an imaginary message from the quitter to the stayer, the purpose
1680 being to generate a dependence from the quitter to the
1681 stayer. */
1682 so = libhb_so_alloc();
1683 tl_assert(so);
1684 /* Send last arg of _so_send as False, since the sending thread
1685 doesn't actually exist any more, so we don't want _so_send to
1686 try taking stack snapshots of it. */
1687 libhb_so_send(hbthr_q, so, True/*strong_send*//*?!? wrt comment above*/);
1688 libhb_so_recv(hbthr_s, so, True/*strong_recv*/);
1689 libhb_so_dealloc(so);
1690
1691 /* Tell libhb that the quitter has been reaped. Note that we might
1692 have to be cleverer about this, to exclude 2nd and subsequent
1693 notifications for the same hbthr_q, in the case where the app is
1694 buggy (calls pthread_join twice or more on the same thread) AND
1695 where libpthread is also buggy and doesn't return ESRCH on
1696 subsequent calls. (If libpthread isn't thusly buggy, then the
1697 wrapper for pthread_join in hg_intercepts.c will stop us getting
1698 notified here multiple times for the same joinee.) See also
1699 comments in helgrind/tests/jointwice.c. */
1700 libhb_joinedwith_done(hbthr_q);
1701 }
1702
1703
1704 static
evh__HG_PTHREAD_JOIN_POST(ThreadId stay_tid,Thread * quit_thr)1705 void evh__HG_PTHREAD_JOIN_POST ( ThreadId stay_tid, Thread* quit_thr )
1706 {
1707 Thread* thr_s;
1708 Thread* thr_q;
1709 Thr* hbthr_s;
1710 Thr* hbthr_q;
1711
1712 if (SHOW_EVENTS >= 1)
1713 VG_(printf)("evh__post_thread_join(stayer=%d, quitter=%p)\n",
1714 (Int)stay_tid, quit_thr );
1715
1716 tl_assert(HG_(is_sane_ThreadId)(stay_tid));
1717
1718 thr_s = map_threads_maybe_lookup( stay_tid );
1719 thr_q = quit_thr;
1720 tl_assert(thr_s != NULL);
1721 tl_assert(thr_q != NULL);
1722 tl_assert(thr_s != thr_q);
1723
1724 hbthr_s = thr_s->hbthr;
1725 hbthr_q = thr_q->hbthr;
1726 tl_assert(hbthr_s != hbthr_q);
1727 tl_assert( libhb_get_Thr_hgthread(hbthr_s) == thr_s );
1728 tl_assert( libhb_get_Thr_hgthread(hbthr_q) == thr_q );
1729
1730 generate_quitter_stayer_dependence (hbthr_q, hbthr_s);
1731
1732 /* evh__pre_thread_ll_exit issues an error message if the exiting
1733 thread holds any locks. No need to check here. */
1734
1735 /* This holds because, at least when using NPTL as the thread
1736 library, we should be notified the low level thread exit before
1737 we hear of any join event on it. The low level exit
1738 notification feeds through into evh__pre_thread_ll_exit,
1739 which should clear the map_threads entry for it. Hence we
1740 expect there to be no map_threads entry at this point. */
1741 tl_assert( map_threads_maybe_reverse_lookup_SLOW(thr_q)
1742 == VG_INVALID_THREADID);
1743
1744 if (HG_(clo_sanity_flags) & SCE_THREADS)
1745 all__sanity_check("evh__post_thread_join-post");
1746 }
1747
1748 static
evh__pre_mem_read(CorePart part,ThreadId tid,const HChar * s,Addr a,SizeT size)1749 void evh__pre_mem_read ( CorePart part, ThreadId tid, const HChar* s,
1750 Addr a, SizeT size) {
1751 if (SHOW_EVENTS >= 2
1752 || (SHOW_EVENTS >= 1 && size != 1))
1753 VG_(printf)("evh__pre_mem_read(ctid=%d, \"%s\", %p, %lu)\n",
1754 (Int)tid, s, (void*)a, size );
1755 shadow_mem_cread_range( map_threads_lookup(tid), a, size);
1756 if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1757 all__sanity_check("evh__pre_mem_read-post");
1758 }
1759
1760 static
evh__pre_mem_read_asciiz(CorePart part,ThreadId tid,const HChar * s,Addr a)1761 void evh__pre_mem_read_asciiz ( CorePart part, ThreadId tid,
1762 const HChar* s, Addr a ) {
1763 Int len;
1764 if (SHOW_EVENTS >= 1)
1765 VG_(printf)("evh__pre_mem_asciiz(ctid=%d, \"%s\", %p)\n",
1766 (Int)tid, s, (void*)a );
1767 // Don't segfault if the string starts in an obviously stupid
1768 // place. Actually we should check the whole string, not just
1769 // the start address, but that's too much trouble. At least
1770 // checking the first byte is better than nothing. See #255009.
1771 if (!VG_(am_is_valid_for_client) (a, 1, VKI_PROT_READ))
1772 return;
1773 len = VG_(strlen)( (HChar*) a );
1774 shadow_mem_cread_range( map_threads_lookup(tid), a, len+1 );
1775 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1776 all__sanity_check("evh__pre_mem_read_asciiz-post");
1777 }
1778
1779 static
evh__pre_mem_write(CorePart part,ThreadId tid,const HChar * s,Addr a,SizeT size)1780 void evh__pre_mem_write ( CorePart part, ThreadId tid, const HChar* s,
1781 Addr a, SizeT size ) {
1782 if (SHOW_EVENTS >= 1)
1783 VG_(printf)("evh__pre_mem_write(ctid=%d, \"%s\", %p, %lu)\n",
1784 (Int)tid, s, (void*)a, size );
1785 shadow_mem_cwrite_range( map_threads_lookup(tid), a, size);
1786 if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1787 all__sanity_check("evh__pre_mem_write-post");
1788 }
1789
1790 static
evh__new_mem_heap(Addr a,SizeT len,Bool is_inited)1791 void evh__new_mem_heap ( Addr a, SizeT len, Bool is_inited ) {
1792 if (SHOW_EVENTS >= 1)
1793 VG_(printf)("evh__new_mem_heap(%p, %lu, inited=%d)\n",
1794 (void*)a, len, (Int)is_inited );
1795 // We ignore the initialisation state (is_inited); that's ok.
1796 shadow_mem_make_New(get_current_Thread(), a, len);
1797 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1798 all__sanity_check("evh__pre_mem_read-post");
1799 }
1800
1801 static
evh__die_mem_heap(Addr a,SizeT len)1802 void evh__die_mem_heap ( Addr a, SizeT len ) {
1803 Thread* thr;
1804 if (SHOW_EVENTS >= 1)
1805 VG_(printf)("evh__die_mem_heap(%p, %lu)\n", (void*)a, len );
1806 thr = get_current_Thread();
1807 tl_assert(thr);
1808 if (HG_(clo_free_is_write)) {
1809 /* Treat frees as if the memory was written immediately prior to
1810 the free. This shakes out more races, specifically, cases
1811 where memory is referenced by one thread, and freed by
1812 another, and there's no observable synchronisation event to
1813 guarantee that the reference happens before the free. */
1814 shadow_mem_cwrite_range(thr, a, len);
1815 }
1816 shadow_mem_make_NoAccess_AHAE( thr, a, len );
1817 /* We used to call instead
1818 shadow_mem_make_NoAccess_NoFX( thr, a, len );
1819 A non-buggy application will not access anymore
1820 the freed memory, and so marking no access is in theory useless.
1821 Not marking freed memory would avoid the overhead for applications
1822 doing mostly malloc/free, as the freed memory should then be recycled
1823 very quickly after marking.
1824 We rather mark it noaccess for the following reasons:
1825 * accessibility bits then always correctly represents the memory
1826 status (e.g. for the client request VALGRIND_HG_GET_ABITS).
1827 * the overhead is reasonable (about 5 seconds per Gb in 1000 bytes
1828 blocks, on a ppc64le, for a unrealistic workload of an application
1829 doing only malloc/free).
1830 * marking no access allows to GC the SecMap, which might improve
1831 performance and/or memory usage.
1832 * we might detect more applications bugs when memory is marked
1833 noaccess.
1834 If needed, we could support here an option --free-is-noaccess=yes|no
1835 to avoid marking freed memory as no access if some applications
1836 would need to avoid the marking noaccess overhead. */
1837
1838 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1839 all__sanity_check("evh__pre_mem_read-post");
1840 }
1841
1842 /* --- Event handlers called from generated code --- */
1843
1844 static VG_REGPARM(1)
evh__mem_help_cread_1(Addr a)1845 void evh__mem_help_cread_1(Addr a) {
1846 Thread* thr = get_current_Thread_in_C_C();
1847 Thr* hbthr = thr->hbthr;
1848 LIBHB_CREAD_1(hbthr, a);
1849 }
1850
1851 static VG_REGPARM(1)
evh__mem_help_cread_2(Addr a)1852 void evh__mem_help_cread_2(Addr a) {
1853 Thread* thr = get_current_Thread_in_C_C();
1854 Thr* hbthr = thr->hbthr;
1855 LIBHB_CREAD_2(hbthr, a);
1856 }
1857
1858 static VG_REGPARM(1)
evh__mem_help_cread_4(Addr a)1859 void evh__mem_help_cread_4(Addr a) {
1860 Thread* thr = get_current_Thread_in_C_C();
1861 Thr* hbthr = thr->hbthr;
1862 LIBHB_CREAD_4(hbthr, a);
1863 }
1864
1865 static VG_REGPARM(1)
evh__mem_help_cread_8(Addr a)1866 void evh__mem_help_cread_8(Addr a) {
1867 Thread* thr = get_current_Thread_in_C_C();
1868 Thr* hbthr = thr->hbthr;
1869 LIBHB_CREAD_8(hbthr, a);
1870 }
1871
1872 static VG_REGPARM(2)
evh__mem_help_cread_N(Addr a,SizeT size)1873 void evh__mem_help_cread_N(Addr a, SizeT size) {
1874 Thread* thr = get_current_Thread_in_C_C();
1875 Thr* hbthr = thr->hbthr;
1876 LIBHB_CREAD_N(hbthr, a, size);
1877 }
1878
1879 static VG_REGPARM(1)
evh__mem_help_cwrite_1(Addr a)1880 void evh__mem_help_cwrite_1(Addr a) {
1881 Thread* thr = get_current_Thread_in_C_C();
1882 Thr* hbthr = thr->hbthr;
1883 LIBHB_CWRITE_1(hbthr, a);
1884 }
1885
1886 static VG_REGPARM(1)
evh__mem_help_cwrite_2(Addr a)1887 void evh__mem_help_cwrite_2(Addr a) {
1888 Thread* thr = get_current_Thread_in_C_C();
1889 Thr* hbthr = thr->hbthr;
1890 LIBHB_CWRITE_2(hbthr, a);
1891 }
1892
1893 static VG_REGPARM(1)
evh__mem_help_cwrite_4(Addr a)1894 void evh__mem_help_cwrite_4(Addr a) {
1895 Thread* thr = get_current_Thread_in_C_C();
1896 Thr* hbthr = thr->hbthr;
1897 LIBHB_CWRITE_4(hbthr, a);
1898 }
1899
1900 static VG_REGPARM(1)
evh__mem_help_cwrite_8(Addr a)1901 void evh__mem_help_cwrite_8(Addr a) {
1902 Thread* thr = get_current_Thread_in_C_C();
1903 Thr* hbthr = thr->hbthr;
1904 LIBHB_CWRITE_8(hbthr, a);
1905 }
1906
1907 static VG_REGPARM(2)
evh__mem_help_cwrite_N(Addr a,SizeT size)1908 void evh__mem_help_cwrite_N(Addr a, SizeT size) {
1909 Thread* thr = get_current_Thread_in_C_C();
1910 Thr* hbthr = thr->hbthr;
1911 LIBHB_CWRITE_N(hbthr, a, size);
1912 }
1913
1914
1915 /* ------------------------------------------------------- */
1916 /* -------------- events to do with mutexes -------------- */
1917 /* ------------------------------------------------------- */
1918
1919 /* EXPOSITION only: by intercepting lock init events we can show the
1920 user where the lock was initialised, rather than only being able to
1921 show where it was first locked. Intercepting lock initialisations
1922 is not necessary for the basic operation of the race checker. */
1923 static
evh__HG_PTHREAD_MUTEX_INIT_POST(ThreadId tid,void * mutex,Word mbRec)1924 void evh__HG_PTHREAD_MUTEX_INIT_POST( ThreadId tid,
1925 void* mutex, Word mbRec )
1926 {
1927 if (SHOW_EVENTS >= 1)
1928 VG_(printf)("evh__hg_PTHREAD_MUTEX_INIT_POST(ctid=%d, mbRec=%ld, %p)\n",
1929 (Int)tid, mbRec, (void*)mutex );
1930 tl_assert(mbRec == 0 || mbRec == 1);
1931 map_locks_lookup_or_create( mbRec ? LK_mbRec : LK_nonRec,
1932 (Addr)mutex, tid );
1933 if (HG_(clo_sanity_flags) & SCE_LOCKS)
1934 all__sanity_check("evh__hg_PTHREAD_MUTEX_INIT_POST");
1935 }
1936
1937 static
evh__HG_PTHREAD_MUTEX_DESTROY_PRE(ThreadId tid,void * mutex,Bool mutex_is_init)1938 void evh__HG_PTHREAD_MUTEX_DESTROY_PRE( ThreadId tid, void* mutex,
1939 Bool mutex_is_init )
1940 {
1941 Thread* thr;
1942 Lock* lk;
1943 if (SHOW_EVENTS >= 1)
1944 VG_(printf)("evh__hg_PTHREAD_MUTEX_DESTROY_PRE"
1945 "(ctid=%d, %p, isInit=%d)\n",
1946 (Int)tid, (void*)mutex, (Int)mutex_is_init );
1947
1948 thr = map_threads_maybe_lookup( tid );
1949 /* cannot fail - Thread* must already exist */
1950 tl_assert( HG_(is_sane_Thread)(thr) );
1951
1952 lk = map_locks_maybe_lookup( (Addr)mutex );
1953
1954 if (lk == NULL && mutex_is_init) {
1955 /* We're destroying a mutex which we don't have any record of,
1956 and which appears to have the value PTHREAD_MUTEX_INITIALIZER.
1957 Assume it never got used, and so we don't need to do anything
1958 more. */
1959 goto out;
1960 }
1961
1962 if (lk == NULL || (lk->kind != LK_nonRec && lk->kind != LK_mbRec)) {
1963 HG_(record_error_Misc)(
1964 thr, "pthread_mutex_destroy with invalid argument" );
1965 }
1966
1967 if (lk) {
1968 tl_assert( HG_(is_sane_LockN)(lk) );
1969 tl_assert( lk->guestaddr == (Addr)mutex );
1970 if (lk->heldBy) {
1971 /* Basically act like we unlocked the lock */
1972 HG_(record_error_Misc)(
1973 thr, "pthread_mutex_destroy of a locked mutex" );
1974 /* remove lock from locksets of all owning threads */
1975 remove_Lock_from_locksets_of_all_owning_Threads( lk );
1976 VG_(deleteBag)( lk->heldBy );
1977 lk->heldBy = NULL;
1978 lk->heldW = False;
1979 lk->acquired_at = NULL;
1980 }
1981 tl_assert( !lk->heldBy );
1982 tl_assert( HG_(is_sane_LockN)(lk) );
1983
1984 if (HG_(clo_track_lockorders))
1985 laog__handle_one_lock_deletion(lk);
1986 map_locks_delete( lk->guestaddr );
1987 del_LockN( lk );
1988 }
1989
1990 out:
1991 if (HG_(clo_sanity_flags) & SCE_LOCKS)
1992 all__sanity_check("evh__hg_PTHREAD_MUTEX_DESTROY_PRE");
1993 }
1994
evh__HG_PTHREAD_MUTEX_LOCK_PRE(ThreadId tid,void * mutex,Word isTryLock)1995 static void evh__HG_PTHREAD_MUTEX_LOCK_PRE ( ThreadId tid,
1996 void* mutex, Word isTryLock )
1997 {
1998 /* Just check the mutex is sane; nothing else to do. */
1999 // 'mutex' may be invalid - not checked by wrapper
2000 Thread* thr;
2001 Lock* lk;
2002 if (SHOW_EVENTS >= 1)
2003 VG_(printf)("evh__hg_PTHREAD_MUTEX_LOCK_PRE(ctid=%d, mutex=%p)\n",
2004 (Int)tid, (void*)mutex );
2005
2006 tl_assert(isTryLock == 0 || isTryLock == 1);
2007 thr = map_threads_maybe_lookup( tid );
2008 tl_assert(thr); /* cannot fail - Thread* must already exist */
2009
2010 lk = map_locks_maybe_lookup( (Addr)mutex );
2011
2012 if (lk && (lk->kind == LK_rdwr)) {
2013 HG_(record_error_Misc)( thr, "pthread_mutex_lock with a "
2014 "pthread_rwlock_t* argument " );
2015 }
2016
2017 if ( lk
2018 && isTryLock == 0
2019 && (lk->kind == LK_nonRec || lk->kind == LK_rdwr)
2020 && lk->heldBy
2021 && lk->heldW
2022 && VG_(elemBag)( lk->heldBy, (UWord)thr ) > 0 ) {
2023 /* uh, it's a non-recursive lock and we already w-hold it, and
2024 this is a real lock operation (not a speculative "tryLock"
2025 kind of thing). Duh. Deadlock coming up; but at least
2026 produce an error message. */
2027 const HChar* errstr = "Attempt to re-lock a "
2028 "non-recursive lock I already hold";
2029 const HChar* auxstr = "Lock was previously acquired";
2030 if (lk->acquired_at) {
2031 HG_(record_error_Misc_w_aux)( thr, errstr, auxstr, lk->acquired_at );
2032 } else {
2033 HG_(record_error_Misc)( thr, errstr );
2034 }
2035 }
2036 }
2037
evh__HG_PTHREAD_MUTEX_LOCK_POST(ThreadId tid,void * mutex)2038 static void evh__HG_PTHREAD_MUTEX_LOCK_POST ( ThreadId tid, void* mutex )
2039 {
2040 // only called if the real library call succeeded - so mutex is sane
2041 Thread* thr;
2042 if (SHOW_EVENTS >= 1)
2043 VG_(printf)("evh__HG_PTHREAD_MUTEX_LOCK_POST(ctid=%d, mutex=%p)\n",
2044 (Int)tid, (void*)mutex );
2045
2046 thr = map_threads_maybe_lookup( tid );
2047 tl_assert(thr); /* cannot fail - Thread* must already exist */
2048
2049 evhH__post_thread_w_acquires_lock(
2050 thr,
2051 LK_mbRec, /* if not known, create new lock with this LockKind */
2052 (Addr)mutex
2053 );
2054 }
2055
evh__HG_PTHREAD_MUTEX_UNLOCK_PRE(ThreadId tid,void * mutex)2056 static void evh__HG_PTHREAD_MUTEX_UNLOCK_PRE ( ThreadId tid, void* mutex )
2057 {
2058 // 'mutex' may be invalid - not checked by wrapper
2059 Thread* thr;
2060 if (SHOW_EVENTS >= 1)
2061 VG_(printf)("evh__HG_PTHREAD_MUTEX_UNLOCK_PRE(ctid=%d, mutex=%p)\n",
2062 (Int)tid, (void*)mutex );
2063
2064 thr = map_threads_maybe_lookup( tid );
2065 tl_assert(thr); /* cannot fail - Thread* must already exist */
2066
2067 evhH__pre_thread_releases_lock( thr, (Addr)mutex, False/*!isRDWR*/ );
2068 }
2069
evh__HG_PTHREAD_MUTEX_UNLOCK_POST(ThreadId tid,void * mutex)2070 static void evh__HG_PTHREAD_MUTEX_UNLOCK_POST ( ThreadId tid, void* mutex )
2071 {
2072 // only called if the real library call succeeded - so mutex is sane
2073 Thread* thr;
2074 if (SHOW_EVENTS >= 1)
2075 VG_(printf)("evh__hg_PTHREAD_MUTEX_UNLOCK_POST(ctid=%d, mutex=%p)\n",
2076 (Int)tid, (void*)mutex );
2077 thr = map_threads_maybe_lookup( tid );
2078 tl_assert(thr); /* cannot fail - Thread* must already exist */
2079
2080 // anything we should do here?
2081 }
2082
2083
2084 /* ------------------------------------------------------- */
2085 /* -------------- events to do with spinlocks ------------ */
2086 /* ------------------------------------------------------- */
2087
2088 /* All a bit of a kludge. Pretend we're really dealing with ordinary
2089 pthread_mutex_t's instead, for the most part. */
2090
evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE(ThreadId tid,void * slock)2091 static void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( ThreadId tid,
2092 void* slock )
2093 {
2094 Thread* thr;
2095 Lock* lk;
2096 /* In glibc's kludgey world, we're either initialising or unlocking
2097 it. Since this is the pre-routine, if it is locked, unlock it
2098 and take a dependence edge. Otherwise, do nothing. */
2099
2100 if (SHOW_EVENTS >= 1)
2101 VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE"
2102 "(ctid=%d, slock=%p)\n",
2103 (Int)tid, (void*)slock );
2104
2105 thr = map_threads_maybe_lookup( tid );
2106 /* cannot fail - Thread* must already exist */;
2107 tl_assert( HG_(is_sane_Thread)(thr) );
2108
2109 lk = map_locks_maybe_lookup( (Addr)slock );
2110 if (lk && lk->heldBy) {
2111 /* it's held. So do the normal pre-unlock actions, as copied
2112 from evh__HG_PTHREAD_MUTEX_UNLOCK_PRE. This stupidly
2113 duplicates the map_locks_maybe_lookup. */
2114 evhH__pre_thread_releases_lock( thr, (Addr)slock,
2115 False/*!isRDWR*/ );
2116 }
2117 }
2118
evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST(ThreadId tid,void * slock)2119 static void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( ThreadId tid,
2120 void* slock )
2121 {
2122 Lock* lk;
2123 /* More kludgery. If the lock has never been seen before, do
2124 actions as per evh__HG_PTHREAD_MUTEX_INIT_POST. Else do
2125 nothing. */
2126
2127 if (SHOW_EVENTS >= 1)
2128 VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_POST"
2129 "(ctid=%d, slock=%p)\n",
2130 (Int)tid, (void*)slock );
2131
2132 lk = map_locks_maybe_lookup( (Addr)slock );
2133 if (!lk) {
2134 map_locks_lookup_or_create( LK_nonRec, (Addr)slock, tid );
2135 }
2136 }
2137
evh__HG_PTHREAD_SPIN_LOCK_PRE(ThreadId tid,void * slock,Word isTryLock)2138 static void evh__HG_PTHREAD_SPIN_LOCK_PRE( ThreadId tid,
2139 void* slock, Word isTryLock )
2140 {
2141 evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, slock, isTryLock );
2142 }
2143
evh__HG_PTHREAD_SPIN_LOCK_POST(ThreadId tid,void * slock)2144 static void evh__HG_PTHREAD_SPIN_LOCK_POST( ThreadId tid,
2145 void* slock )
2146 {
2147 evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, slock );
2148 }
2149
evh__HG_PTHREAD_SPIN_DESTROY_PRE(ThreadId tid,void * slock)2150 static void evh__HG_PTHREAD_SPIN_DESTROY_PRE( ThreadId tid,
2151 void* slock )
2152 {
2153 evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, slock, 0/*!isInit*/ );
2154 }
2155
2156
2157 /* ----------------------------------------------------- */
2158 /* --------------- events to do with CVs --------------- */
2159 /* ----------------------------------------------------- */
2160
2161 /* A mapping from CV to (the SO associated with it, plus some
2162 auxiliary data for error checking). When the CV is
2163 signalled/broadcasted upon, we do a 'send' into the SO, and when a
2164 wait on it completes, we do a 'recv' from the SO. This is believed
2165 to give the correct happens-before events arising from CV
2166 signallings/broadcasts.
2167 */
2168
2169 /* .so is the SO for this CV.
2170 .mx_ga is the associated mutex, when .nWaiters > 0
2171
2172 POSIX says effectively that the first pthread_cond_{timed}wait call
2173 causes a dynamic binding between the CV and the mutex, and that
2174 lasts until such time as the waiter count falls to zero. Hence
2175 need to keep track of the number of waiters in order to do
2176 consistency tracking. */
2177 typedef
2178 struct {
2179 SO* so; /* libhb-allocated SO */
2180 void* mx_ga; /* addr of associated mutex, if any */
2181 UWord nWaiters; /* # threads waiting on the CV */
2182 }
2183 CVInfo;
2184
2185
2186 /* pthread_cond_t* -> CVInfo* */
2187 static WordFM* map_cond_to_CVInfo = NULL;
2188
map_cond_to_CVInfo_INIT(void)2189 static void map_cond_to_CVInfo_INIT ( void ) {
2190 if (UNLIKELY(map_cond_to_CVInfo == NULL)) {
2191 map_cond_to_CVInfo = VG_(newFM)( HG_(zalloc),
2192 "hg.mctCI.1", HG_(free), NULL );
2193 }
2194 }
2195
map_cond_to_CVInfo_lookup_or_alloc(void * cond)2196 static CVInfo* map_cond_to_CVInfo_lookup_or_alloc ( void* cond ) {
2197 UWord key, val;
2198 map_cond_to_CVInfo_INIT();
2199 if (VG_(lookupFM)( map_cond_to_CVInfo, &key, &val, (UWord)cond )) {
2200 tl_assert(key == (UWord)cond);
2201 return (CVInfo*)val;
2202 } else {
2203 SO* so = libhb_so_alloc();
2204 CVInfo* cvi = HG_(zalloc)("hg.mctCloa.1", sizeof(CVInfo));
2205 cvi->so = so;
2206 cvi->mx_ga = 0;
2207 VG_(addToFM)( map_cond_to_CVInfo, (UWord)cond, (UWord)cvi );
2208 return cvi;
2209 }
2210 }
2211
map_cond_to_CVInfo_lookup_NO_alloc(void * cond)2212 static CVInfo* map_cond_to_CVInfo_lookup_NO_alloc ( void* cond ) {
2213 UWord key, val;
2214 map_cond_to_CVInfo_INIT();
2215 if (VG_(lookupFM)( map_cond_to_CVInfo, &key, &val, (UWord)cond )) {
2216 tl_assert(key == (UWord)cond);
2217 return (CVInfo*)val;
2218 } else {
2219 return NULL;
2220 }
2221 }
2222
map_cond_to_CVInfo_delete(ThreadId tid,void * cond,Bool cond_is_init)2223 static void map_cond_to_CVInfo_delete ( ThreadId tid,
2224 void* cond, Bool cond_is_init ) {
2225 Thread* thr;
2226 UWord keyW, valW;
2227
2228 thr = map_threads_maybe_lookup( tid );
2229 tl_assert(thr); /* cannot fail - Thread* must already exist */
2230
2231 map_cond_to_CVInfo_INIT();
2232 if (VG_(lookupFM)( map_cond_to_CVInfo, &keyW, &valW, (UWord)cond )) {
2233 CVInfo* cvi = (CVInfo*)valW;
2234 tl_assert(keyW == (UWord)cond);
2235 tl_assert(cvi);
2236 tl_assert(cvi->so);
2237 if (cvi->nWaiters > 0) {
2238 HG_(record_error_Misc)(
2239 thr, "pthread_cond_destroy:"
2240 " destruction of condition variable being waited upon");
2241 /* Destroying a cond var being waited upon outcome is EBUSY and
2242 variable is not destroyed. */
2243 return;
2244 }
2245 if (!VG_(delFromFM)( map_cond_to_CVInfo, &keyW, &valW, (UWord)cond ))
2246 tl_assert(0); // cond var found above, and not here ???
2247 libhb_so_dealloc(cvi->so);
2248 cvi->mx_ga = 0;
2249 HG_(free)(cvi);
2250 } else {
2251 /* We have no record of this CV. So complain about it
2252 .. except, don't bother to complain if it has exactly the
2253 value PTHREAD_COND_INITIALIZER, since it might be that the CV
2254 was initialised like that but never used. */
2255 if (!cond_is_init) {
2256 HG_(record_error_Misc)(
2257 thr, "pthread_cond_destroy: destruction of unknown cond var");
2258 }
2259 }
2260 }
2261
evh__HG_PTHREAD_COND_SIGNAL_PRE(ThreadId tid,void * cond)2262 static void evh__HG_PTHREAD_COND_SIGNAL_PRE ( ThreadId tid, void* cond )
2263 {
2264 /* 'tid' has signalled on 'cond'. As per the comment above, bind
2265 cond to a SO if it is not already so bound, and 'send' on the
2266 SO. This is later used by other thread(s) which successfully
2267 exit from a pthread_cond_wait on the same cv; then they 'recv'
2268 from the SO, thereby acquiring a dependency on this signalling
2269 event. */
2270 Thread* thr;
2271 CVInfo* cvi;
2272 //Lock* lk;
2273
2274 if (SHOW_EVENTS >= 1)
2275 VG_(printf)("evh__HG_PTHREAD_COND_SIGNAL_PRE(ctid=%d, cond=%p)\n",
2276 (Int)tid, (void*)cond );
2277
2278 thr = map_threads_maybe_lookup( tid );
2279 tl_assert(thr); /* cannot fail - Thread* must already exist */
2280
2281 cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2282 tl_assert(cvi);
2283 tl_assert(cvi->so);
2284
2285 // error-if: mutex is bogus
2286 // error-if: mutex is not locked
2287 // Hmm. POSIX doesn't actually say that it's an error to call
2288 // pthread_cond_signal with the associated mutex being unlocked.
2289 // Although it does say that it should be "if consistent scheduling
2290 // is desired." For that reason, print "dubious" if the lock isn't
2291 // held by any thread. Skip the "dubious" if it is held by some
2292 // other thread; that sounds straight-out wrong.
2293 //
2294 // Anybody who writes code that signals on a CV without holding
2295 // the associated MX needs to be shipped off to a lunatic asylum
2296 // ASAP, even though POSIX doesn't actually declare such behaviour
2297 // illegal -- it makes code extremely difficult to understand/
2298 // reason about. In particular it puts the signalling thread in
2299 // a situation where it is racing against the released waiter
2300 // as soon as the signalling is done, and so there needs to be
2301 // some auxiliary synchronisation mechanism in the program that
2302 // makes this safe -- or the race(s) need to be harmless, or
2303 // probably nonexistent.
2304 //
2305 if (1) {
2306 Lock* lk = NULL;
2307 if (cvi->mx_ga != 0) {
2308 lk = map_locks_maybe_lookup( (Addr)cvi->mx_ga );
2309 }
2310 /* note: lk could be NULL. Be careful. */
2311 if (lk) {
2312 if (lk->kind == LK_rdwr) {
2313 HG_(record_error_Misc)(thr,
2314 "pthread_cond_{signal,broadcast}: associated lock is a rwlock");
2315 }
2316 if (lk->heldBy == NULL) {
2317 HG_(record_error_Misc)(thr,
2318 "pthread_cond_{signal,broadcast}: dubious: "
2319 "associated lock is not held by any thread");
2320 }
2321 if (lk->heldBy != NULL && 0 == VG_(elemBag)(lk->heldBy, (UWord)thr)) {
2322 HG_(record_error_Misc)(thr,
2323 "pthread_cond_{signal,broadcast}: "
2324 "associated lock is not held by calling thread");
2325 }
2326 } else {
2327 /* Couldn't even find the damn thing. */
2328 // But actually .. that's not necessarily an error. We don't
2329 // know the (CV,MX) binding until a pthread_cond_wait or bcast
2330 // shows us what it is, and if that may not have happened yet.
2331 // So just keep quiet in this circumstance.
2332 //HG_(record_error_Misc)( thr,
2333 // "pthread_cond_{signal,broadcast}: "
2334 // "no or invalid mutex associated with cond");
2335 }
2336 }
2337
2338 libhb_so_send( thr->hbthr, cvi->so, True/*strong_send*/ );
2339 }
2340
2341 /* returns True if it reckons 'mutex' is valid and held by this
2342 thread, else False */
evh__HG_PTHREAD_COND_WAIT_PRE(ThreadId tid,void * cond,void * mutex)2343 static Bool evh__HG_PTHREAD_COND_WAIT_PRE ( ThreadId tid,
2344 void* cond, void* mutex )
2345 {
2346 Thread* thr;
2347 Lock* lk;
2348 Bool lk_valid = True;
2349 CVInfo* cvi;
2350
2351 if (SHOW_EVENTS >= 1)
2352 VG_(printf)("evh__hg_PTHREAD_COND_WAIT_PRE"
2353 "(ctid=%d, cond=%p, mutex=%p)\n",
2354 (Int)tid, (void*)cond, (void*)mutex );
2355
2356 thr = map_threads_maybe_lookup( tid );
2357 tl_assert(thr); /* cannot fail - Thread* must already exist */
2358
2359 lk = map_locks_maybe_lookup( (Addr)mutex );
2360
2361 /* Check for stupid mutex arguments. There are various ways to be
2362 a bozo. Only complain once, though, even if more than one thing
2363 is wrong. */
2364 if (lk == NULL) {
2365 lk_valid = False;
2366 HG_(record_error_Misc)(
2367 thr,
2368 "pthread_cond_{timed}wait called with invalid mutex" );
2369 } else {
2370 tl_assert( HG_(is_sane_LockN)(lk) );
2371 if (lk->kind == LK_rdwr) {
2372 lk_valid = False;
2373 HG_(record_error_Misc)(
2374 thr, "pthread_cond_{timed}wait called with mutex "
2375 "of type pthread_rwlock_t*" );
2376 } else
2377 if (lk->heldBy == NULL) {
2378 lk_valid = False;
2379 HG_(record_error_Misc)(
2380 thr, "pthread_cond_{timed}wait called with un-held mutex");
2381 } else
2382 if (lk->heldBy != NULL
2383 && VG_(elemBag)( lk->heldBy, (UWord)thr ) == 0) {
2384 lk_valid = False;
2385 HG_(record_error_Misc)(
2386 thr, "pthread_cond_{timed}wait called with mutex "
2387 "held by a different thread" );
2388 }
2389 }
2390
2391 // error-if: cond is also associated with a different mutex
2392 cvi = map_cond_to_CVInfo_lookup_or_alloc(cond);
2393 tl_assert(cvi);
2394 tl_assert(cvi->so);
2395 if (cvi->nWaiters == 0) {
2396 /* form initial (CV,MX) binding */
2397 cvi->mx_ga = mutex;
2398 }
2399 else /* check existing (CV,MX) binding */
2400 if (cvi->mx_ga != mutex) {
2401 HG_(record_error_Misc)(
2402 thr, "pthread_cond_{timed}wait: cond is associated "
2403 "with a different mutex");
2404 }
2405 cvi->nWaiters++;
2406
2407 return lk_valid;
2408 }
2409
evh__HG_PTHREAD_COND_WAIT_POST(ThreadId tid,void * cond,void * mutex,Bool timeout)2410 static void evh__HG_PTHREAD_COND_WAIT_POST ( ThreadId tid,
2411 void* cond, void* mutex,
2412 Bool timeout)
2413 {
2414 /* A pthread_cond_wait(cond, mutex) completed successfully. Find
2415 the SO for this cond, and 'recv' from it so as to acquire a
2416 dependency edge back to the signaller/broadcaster. */
2417 Thread* thr;
2418 CVInfo* cvi;
2419
2420 if (SHOW_EVENTS >= 1)
2421 VG_(printf)("evh__HG_PTHREAD_COND_WAIT_POST"
2422 "(ctid=%d, cond=%p, mutex=%p)\n, timeout=%d",
2423 (Int)tid, (void*)cond, (void*)mutex, (Int)timeout );
2424
2425 thr = map_threads_maybe_lookup( tid );
2426 tl_assert(thr); /* cannot fail - Thread* must already exist */
2427
2428 // error-if: cond is also associated with a different mutex
2429
2430 cvi = map_cond_to_CVInfo_lookup_NO_alloc( cond );
2431 if (!cvi) {
2432 /* This could be either a bug in helgrind or the guest application
2433 that did an error (e.g. cond var was destroyed by another thread.
2434 Let's assume helgrind is perfect ...
2435 Note that this is similar to drd behaviour. */
2436 HG_(record_error_Misc)(thr, "condition variable has been destroyed while"
2437 " being waited upon");
2438 return;
2439 }
2440
2441 tl_assert(cvi);
2442 tl_assert(cvi->so);
2443 tl_assert(cvi->nWaiters > 0);
2444
2445 if (!timeout && !libhb_so_everSent(cvi->so)) {
2446 /* Hmm. How can a wait on 'cond' succeed if nobody signalled
2447 it? If this happened it would surely be a bug in the threads
2448 library. Or one of those fabled "spurious wakeups". */
2449 HG_(record_error_Misc)( thr, "Bug in libpthread: pthread_cond_wait "
2450 "succeeded"
2451 " without prior pthread_cond_post");
2452 }
2453
2454 /* anyway, acquire a dependency on it. */
2455 libhb_so_recv( thr->hbthr, cvi->so, True/*strong_recv*/ );
2456
2457 cvi->nWaiters--;
2458 }
2459
evh__HG_PTHREAD_COND_INIT_POST(ThreadId tid,void * cond,void * cond_attr)2460 static void evh__HG_PTHREAD_COND_INIT_POST ( ThreadId tid,
2461 void* cond, void* cond_attr )
2462 {
2463 CVInfo* cvi;
2464
2465 if (SHOW_EVENTS >= 1)
2466 VG_(printf)("evh__HG_PTHREAD_COND_INIT_POST"
2467 "(ctid=%d, cond=%p, cond_attr=%p)\n",
2468 (Int)tid, (void*)cond, (void*) cond_attr );
2469
2470 cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2471 tl_assert (cvi);
2472 tl_assert (cvi->so);
2473 }
2474
2475
evh__HG_PTHREAD_COND_DESTROY_PRE(ThreadId tid,void * cond,Bool cond_is_init)2476 static void evh__HG_PTHREAD_COND_DESTROY_PRE ( ThreadId tid,
2477 void* cond, Bool cond_is_init )
2478 {
2479 /* Deal with destroy events. The only purpose is to free storage
2480 associated with the CV, so as to avoid any possible resource
2481 leaks. */
2482 if (SHOW_EVENTS >= 1)
2483 VG_(printf)("evh__HG_PTHREAD_COND_DESTROY_PRE"
2484 "(ctid=%d, cond=%p, cond_is_init=%d)\n",
2485 (Int)tid, (void*)cond, (Int)cond_is_init );
2486
2487 map_cond_to_CVInfo_delete( tid, cond, cond_is_init );
2488 }
2489
2490
2491 /* ------------------------------------------------------- */
2492 /* -------------- events to do with rwlocks -------------- */
2493 /* ------------------------------------------------------- */
2494
2495 /* EXPOSITION only */
2496 static
evh__HG_PTHREAD_RWLOCK_INIT_POST(ThreadId tid,void * rwl)2497 void evh__HG_PTHREAD_RWLOCK_INIT_POST( ThreadId tid, void* rwl )
2498 {
2499 if (SHOW_EVENTS >= 1)
2500 VG_(printf)("evh__hg_PTHREAD_RWLOCK_INIT_POST(ctid=%d, %p)\n",
2501 (Int)tid, (void*)rwl );
2502 map_locks_lookup_or_create( LK_rdwr, (Addr)rwl, tid );
2503 if (HG_(clo_sanity_flags) & SCE_LOCKS)
2504 all__sanity_check("evh__hg_PTHREAD_RWLOCK_INIT_POST");
2505 }
2506
2507 static
evh__HG_PTHREAD_RWLOCK_DESTROY_PRE(ThreadId tid,void * rwl)2508 void evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( ThreadId tid, void* rwl )
2509 {
2510 Thread* thr;
2511 Lock* lk;
2512 if (SHOW_EVENTS >= 1)
2513 VG_(printf)("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE(ctid=%d, %p)\n",
2514 (Int)tid, (void*)rwl );
2515
2516 thr = map_threads_maybe_lookup( tid );
2517 /* cannot fail - Thread* must already exist */
2518 tl_assert( HG_(is_sane_Thread)(thr) );
2519
2520 lk = map_locks_maybe_lookup( (Addr)rwl );
2521
2522 if (lk == NULL || lk->kind != LK_rdwr) {
2523 HG_(record_error_Misc)(
2524 thr, "pthread_rwlock_destroy with invalid argument" );
2525 }
2526
2527 if (lk) {
2528 tl_assert( HG_(is_sane_LockN)(lk) );
2529 tl_assert( lk->guestaddr == (Addr)rwl );
2530 if (lk->heldBy) {
2531 /* Basically act like we unlocked the lock */
2532 HG_(record_error_Misc)(
2533 thr, "pthread_rwlock_destroy of a locked mutex" );
2534 /* remove lock from locksets of all owning threads */
2535 remove_Lock_from_locksets_of_all_owning_Threads( lk );
2536 VG_(deleteBag)( lk->heldBy );
2537 lk->heldBy = NULL;
2538 lk->heldW = False;
2539 lk->acquired_at = NULL;
2540 }
2541 tl_assert( !lk->heldBy );
2542 tl_assert( HG_(is_sane_LockN)(lk) );
2543
2544 if (HG_(clo_track_lockorders))
2545 laog__handle_one_lock_deletion(lk);
2546 map_locks_delete( lk->guestaddr );
2547 del_LockN( lk );
2548 }
2549
2550 if (HG_(clo_sanity_flags) & SCE_LOCKS)
2551 all__sanity_check("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE");
2552 }
2553
2554 static
evh__HG_PTHREAD_RWLOCK_LOCK_PRE(ThreadId tid,void * rwl,Word isW,Word isTryLock)2555 void evh__HG_PTHREAD_RWLOCK_LOCK_PRE ( ThreadId tid,
2556 void* rwl,
2557 Word isW, Word isTryLock )
2558 {
2559 /* Just check the rwl is sane; nothing else to do. */
2560 // 'rwl' may be invalid - not checked by wrapper
2561 Thread* thr;
2562 Lock* lk;
2563 if (SHOW_EVENTS >= 1)
2564 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_PRE(ctid=%d, isW=%d, %p)\n",
2565 (Int)tid, (Int)isW, (void*)rwl );
2566
2567 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
2568 tl_assert(isTryLock == 0 || isTryLock == 1); /* assured us by wrapper */
2569 thr = map_threads_maybe_lookup( tid );
2570 tl_assert(thr); /* cannot fail - Thread* must already exist */
2571
2572 lk = map_locks_maybe_lookup( (Addr)rwl );
2573 if ( lk
2574 && (lk->kind == LK_nonRec || lk->kind == LK_mbRec) ) {
2575 /* Wrong kind of lock. Duh. */
2576 HG_(record_error_Misc)(
2577 thr, "pthread_rwlock_{rd,rw}lock with a "
2578 "pthread_mutex_t* argument " );
2579 }
2580 }
2581
2582 static
evh__HG_PTHREAD_RWLOCK_LOCK_POST(ThreadId tid,void * rwl,Word isW)2583 void evh__HG_PTHREAD_RWLOCK_LOCK_POST ( ThreadId tid, void* rwl, Word isW )
2584 {
2585 // only called if the real library call succeeded - so mutex is sane
2586 Thread* thr;
2587 if (SHOW_EVENTS >= 1)
2588 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_POST(ctid=%d, isW=%d, %p)\n",
2589 (Int)tid, (Int)isW, (void*)rwl );
2590
2591 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
2592 thr = map_threads_maybe_lookup( tid );
2593 tl_assert(thr); /* cannot fail - Thread* must already exist */
2594
2595 (isW ? evhH__post_thread_w_acquires_lock
2596 : evhH__post_thread_r_acquires_lock)(
2597 thr,
2598 LK_rdwr, /* if not known, create new lock with this LockKind */
2599 (Addr)rwl
2600 );
2601 }
2602
evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE(ThreadId tid,void * rwl)2603 static void evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE ( ThreadId tid, void* rwl )
2604 {
2605 // 'rwl' may be invalid - not checked by wrapper
2606 Thread* thr;
2607 if (SHOW_EVENTS >= 1)
2608 VG_(printf)("evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE(ctid=%d, rwl=%p)\n",
2609 (Int)tid, (void*)rwl );
2610
2611 thr = map_threads_maybe_lookup( tid );
2612 tl_assert(thr); /* cannot fail - Thread* must already exist */
2613
2614 evhH__pre_thread_releases_lock( thr, (Addr)rwl, True/*isRDWR*/ );
2615 }
2616
evh__HG_PTHREAD_RWLOCK_UNLOCK_POST(ThreadId tid,void * rwl)2617 static void evh__HG_PTHREAD_RWLOCK_UNLOCK_POST ( ThreadId tid, void* rwl )
2618 {
2619 // only called if the real library call succeeded - so mutex is sane
2620 Thread* thr;
2621 if (SHOW_EVENTS >= 1)
2622 VG_(printf)("evh__hg_PTHREAD_RWLOCK_UNLOCK_POST(ctid=%d, rwl=%p)\n",
2623 (Int)tid, (void*)rwl );
2624 thr = map_threads_maybe_lookup( tid );
2625 tl_assert(thr); /* cannot fail - Thread* must already exist */
2626
2627 // anything we should do here?
2628 }
2629
2630
2631 /* ---------------------------------------------------------- */
2632 /* -------------- events to do with semaphores -------------- */
2633 /* ---------------------------------------------------------- */
2634
2635 /* This is similar to but not identical to the handling for condition
2636 variables. */
2637
2638 /* For each semaphore, we maintain a stack of SOs. When a 'post'
2639 operation is done on a semaphore (unlocking, essentially), a new SO
2640 is created for the posting thread, the posting thread does a strong
2641 send to it (which merely installs the posting thread's VC in the
2642 SO), and the SO is pushed on the semaphore's stack.
2643
2644 Later, when a (probably different) thread completes 'wait' on the
2645 semaphore, we pop a SO off the semaphore's stack (which should be
2646 nonempty), and do a strong recv from it. This mechanism creates
2647 dependencies between posters and waiters of the semaphore.
2648
2649 It may not be necessary to use a stack - perhaps a bag of SOs would
2650 do. But we do need to keep track of how many unused-up posts have
2651 happened for the semaphore.
2652
2653 Imagine T1 and T2 both post once on a semaphore S, and T3 waits
2654 twice on S. T3 cannot complete its waits without both T1 and T2
2655 posting. The above mechanism will ensure that T3 acquires
2656 dependencies on both T1 and T2.
2657
2658 When a semaphore is initialised with value N, we do as if we'd
2659 posted N times on the semaphore: basically create N SOs and do a
2660 strong send to all of then. This allows up to N waits on the
2661 semaphore to acquire a dependency on the initialisation point,
2662 which AFAICS is the correct behaviour.
2663
2664 We don't emit an error for DESTROY_PRE on a semaphore we don't know
2665 about. We should.
2666 */
2667
2668 /* sem_t* -> XArray* SO* */
2669 static WordFM* map_sem_to_SO_stack = NULL;
2670
map_sem_to_SO_stack_INIT(void)2671 static void map_sem_to_SO_stack_INIT ( void ) {
2672 if (map_sem_to_SO_stack == NULL) {
2673 map_sem_to_SO_stack = VG_(newFM)( HG_(zalloc), "hg.mstSs.1",
2674 HG_(free), NULL );
2675 }
2676 }
2677
push_SO_for_sem(void * sem,SO * so)2678 static void push_SO_for_sem ( void* sem, SO* so ) {
2679 UWord keyW;
2680 XArray* xa;
2681 tl_assert(so);
2682 map_sem_to_SO_stack_INIT();
2683 if (VG_(lookupFM)( map_sem_to_SO_stack,
2684 &keyW, (UWord*)&xa, (UWord)sem )) {
2685 tl_assert(keyW == (UWord)sem);
2686 tl_assert(xa);
2687 VG_(addToXA)( xa, &so );
2688 } else {
2689 xa = VG_(newXA)( HG_(zalloc), "hg.pSfs.1", HG_(free), sizeof(SO*) );
2690 VG_(addToXA)( xa, &so );
2691 VG_(addToFM)( map_sem_to_SO_stack, (UWord)sem, (UWord)xa );
2692 }
2693 }
2694
mb_pop_SO_for_sem(void * sem)2695 static SO* mb_pop_SO_for_sem ( void* sem ) {
2696 UWord keyW;
2697 XArray* xa;
2698 SO* so;
2699 map_sem_to_SO_stack_INIT();
2700 if (VG_(lookupFM)( map_sem_to_SO_stack,
2701 &keyW, (UWord*)&xa, (UWord)sem )) {
2702 /* xa is the stack for this semaphore. */
2703 Word sz;
2704 tl_assert(keyW == (UWord)sem);
2705 sz = VG_(sizeXA)( xa );
2706 tl_assert(sz >= 0);
2707 if (sz == 0)
2708 return NULL; /* odd, the stack is empty */
2709 so = *(SO**)VG_(indexXA)( xa, sz-1 );
2710 tl_assert(so);
2711 VG_(dropTailXA)( xa, 1 );
2712 return so;
2713 } else {
2714 /* hmm, that's odd. No stack for this semaphore. */
2715 return NULL;
2716 }
2717 }
2718
evh__HG_POSIX_SEM_DESTROY_PRE(ThreadId tid,void * sem)2719 static void evh__HG_POSIX_SEM_DESTROY_PRE ( ThreadId tid, void* sem )
2720 {
2721 UWord keyW, valW;
2722 SO* so;
2723
2724 if (SHOW_EVENTS >= 1)
2725 VG_(printf)("evh__HG_POSIX_SEM_DESTROY_PRE(ctid=%d, sem=%p)\n",
2726 (Int)tid, (void*)sem );
2727
2728 map_sem_to_SO_stack_INIT();
2729
2730 /* Empty out the semaphore's SO stack. This way of doing it is
2731 stupid, but at least it's easy. */
2732 while (1) {
2733 so = mb_pop_SO_for_sem( sem );
2734 if (!so) break;
2735 libhb_so_dealloc(so);
2736 }
2737
2738 if (VG_(delFromFM)( map_sem_to_SO_stack, &keyW, &valW, (UWord)sem )) {
2739 XArray* xa = (XArray*)valW;
2740 tl_assert(keyW == (UWord)sem);
2741 tl_assert(xa);
2742 tl_assert(VG_(sizeXA)(xa) == 0); /* preceding loop just emptied it */
2743 VG_(deleteXA)(xa);
2744 }
2745 }
2746
2747 static
evh__HG_POSIX_SEM_INIT_POST(ThreadId tid,void * sem,UWord value)2748 void evh__HG_POSIX_SEM_INIT_POST ( ThreadId tid, void* sem, UWord value )
2749 {
2750 SO* so;
2751 Thread* thr;
2752
2753 if (SHOW_EVENTS >= 1)
2754 VG_(printf)("evh__HG_POSIX_SEM_INIT_POST(ctid=%d, sem=%p, value=%lu)\n",
2755 (Int)tid, (void*)sem, value );
2756
2757 thr = map_threads_maybe_lookup( tid );
2758 tl_assert(thr); /* cannot fail - Thread* must already exist */
2759
2760 /* Empty out the semaphore's SO stack. This way of doing it is
2761 stupid, but at least it's easy. */
2762 while (1) {
2763 so = mb_pop_SO_for_sem( sem );
2764 if (!so) break;
2765 libhb_so_dealloc(so);
2766 }
2767
2768 /* If we don't do this check, the following while loop runs us out
2769 of memory for stupid initial values of 'value'. */
2770 if (value > 10000) {
2771 HG_(record_error_Misc)(
2772 thr, "sem_init: initial value exceeds 10000; using 10000" );
2773 value = 10000;
2774 }
2775
2776 /* Now create 'valid' new SOs for the thread, do a strong send to
2777 each of them, and push them all on the stack. */
2778 for (; value > 0; value--) {
2779 Thr* hbthr = thr->hbthr;
2780 tl_assert(hbthr);
2781
2782 so = libhb_so_alloc();
2783 libhb_so_send( hbthr, so, True/*strong send*/ );
2784 push_SO_for_sem( sem, so );
2785 }
2786 }
2787
evh__HG_POSIX_SEM_POST_PRE(ThreadId tid,void * sem)2788 static void evh__HG_POSIX_SEM_POST_PRE ( ThreadId tid, void* sem )
2789 {
2790 /* 'tid' has posted on 'sem'. Create a new SO, do a strong send to
2791 it (iow, write our VC into it, then tick ours), and push the SO
2792 on on a stack of SOs associated with 'sem'. This is later used
2793 by other thread(s) which successfully exit from a sem_wait on
2794 the same sem; by doing a strong recv from SOs popped of the
2795 stack, they acquire dependencies on the posting thread
2796 segment(s). */
2797
2798 Thread* thr;
2799 SO* so;
2800 Thr* hbthr;
2801
2802 if (SHOW_EVENTS >= 1)
2803 VG_(printf)("evh__HG_POSIX_SEM_POST_PRE(ctid=%d, sem=%p)\n",
2804 (Int)tid, (void*)sem );
2805
2806 thr = map_threads_maybe_lookup( tid );
2807 tl_assert(thr); /* cannot fail - Thread* must already exist */
2808
2809 // error-if: sem is bogus
2810
2811 hbthr = thr->hbthr;
2812 tl_assert(hbthr);
2813
2814 so = libhb_so_alloc();
2815 libhb_so_send( hbthr, so, True/*strong send*/ );
2816 push_SO_for_sem( sem, so );
2817 }
2818
evh__HG_POSIX_SEM_WAIT_POST(ThreadId tid,void * sem)2819 static void evh__HG_POSIX_SEM_WAIT_POST ( ThreadId tid, void* sem )
2820 {
2821 /* A sem_wait(sem) completed successfully. Pop the posting-SO for
2822 the 'sem' from this semaphore's SO-stack, and do a strong recv
2823 from it. This creates a dependency back to one of the post-ers
2824 for the semaphore. */
2825
2826 Thread* thr;
2827 SO* so;
2828 Thr* hbthr;
2829
2830 if (SHOW_EVENTS >= 1)
2831 VG_(printf)("evh__HG_POSIX_SEM_WAIT_POST(ctid=%d, sem=%p)\n",
2832 (Int)tid, (void*)sem );
2833
2834 thr = map_threads_maybe_lookup( tid );
2835 tl_assert(thr); /* cannot fail - Thread* must already exist */
2836
2837 // error-if: sem is bogus
2838
2839 so = mb_pop_SO_for_sem( sem );
2840
2841 if (so) {
2842 hbthr = thr->hbthr;
2843 tl_assert(hbthr);
2844
2845 libhb_so_recv( hbthr, so, True/*strong recv*/ );
2846 libhb_so_dealloc(so);
2847 } else {
2848 /* Hmm. How can a wait on 'sem' succeed if nobody posted to it?
2849 If this happened it would surely be a bug in the threads
2850 library. */
2851 HG_(record_error_Misc)(
2852 thr, "Bug in libpthread: sem_wait succeeded on"
2853 " semaphore without prior sem_post");
2854 }
2855 }
2856
2857
2858 /* -------------------------------------------------------- */
2859 /* -------------- events to do with barriers -------------- */
2860 /* -------------------------------------------------------- */
2861
2862 typedef
2863 struct {
2864 Bool initted; /* has it yet been initted by guest? */
2865 Bool resizable; /* is resizing allowed? */
2866 UWord size; /* declared size */
2867 XArray* waiting; /* XA of Thread*. # present is 0 .. .size */
2868 }
2869 Bar;
2870
new_Bar(void)2871 static Bar* new_Bar ( void ) {
2872 Bar* bar = HG_(zalloc)( "hg.nB.1 (new_Bar)", sizeof(Bar) );
2873 /* all fields are zero */
2874 tl_assert(bar->initted == False);
2875 return bar;
2876 }
2877
delete_Bar(Bar * bar)2878 static void delete_Bar ( Bar* bar ) {
2879 tl_assert(bar);
2880 if (bar->waiting)
2881 VG_(deleteXA)(bar->waiting);
2882 HG_(free)(bar);
2883 }
2884
2885 /* A mapping which stores auxiliary data for barriers. */
2886
2887 /* pthread_barrier_t* -> Bar* */
2888 static WordFM* map_barrier_to_Bar = NULL;
2889
map_barrier_to_Bar_INIT(void)2890 static void map_barrier_to_Bar_INIT ( void ) {
2891 if (UNLIKELY(map_barrier_to_Bar == NULL)) {
2892 map_barrier_to_Bar = VG_(newFM)( HG_(zalloc),
2893 "hg.mbtBI.1", HG_(free), NULL );
2894 }
2895 }
2896
map_barrier_to_Bar_lookup_or_alloc(void * barrier)2897 static Bar* map_barrier_to_Bar_lookup_or_alloc ( void* barrier ) {
2898 UWord key, val;
2899 map_barrier_to_Bar_INIT();
2900 if (VG_(lookupFM)( map_barrier_to_Bar, &key, &val, (UWord)barrier )) {
2901 tl_assert(key == (UWord)barrier);
2902 return (Bar*)val;
2903 } else {
2904 Bar* bar = new_Bar();
2905 VG_(addToFM)( map_barrier_to_Bar, (UWord)barrier, (UWord)bar );
2906 return bar;
2907 }
2908 }
2909
map_barrier_to_Bar_delete(void * barrier)2910 static void map_barrier_to_Bar_delete ( void* barrier ) {
2911 UWord keyW, valW;
2912 map_barrier_to_Bar_INIT();
2913 if (VG_(delFromFM)( map_barrier_to_Bar, &keyW, &valW, (UWord)barrier )) {
2914 Bar* bar = (Bar*)valW;
2915 tl_assert(keyW == (UWord)barrier);
2916 delete_Bar(bar);
2917 }
2918 }
2919
2920
evh__HG_PTHREAD_BARRIER_INIT_PRE(ThreadId tid,void * barrier,UWord count,UWord resizable)2921 static void evh__HG_PTHREAD_BARRIER_INIT_PRE ( ThreadId tid,
2922 void* barrier,
2923 UWord count,
2924 UWord resizable )
2925 {
2926 Thread* thr;
2927 Bar* bar;
2928
2929 if (SHOW_EVENTS >= 1)
2930 VG_(printf)("evh__HG_PTHREAD_BARRIER_INIT_PRE"
2931 "(tid=%d, barrier=%p, count=%lu, resizable=%lu)\n",
2932 (Int)tid, (void*)barrier, count, resizable );
2933
2934 thr = map_threads_maybe_lookup( tid );
2935 tl_assert(thr); /* cannot fail - Thread* must already exist */
2936
2937 if (count == 0) {
2938 HG_(record_error_Misc)(
2939 thr, "pthread_barrier_init: 'count' argument is zero"
2940 );
2941 }
2942
2943 if (resizable != 0 && resizable != 1) {
2944 HG_(record_error_Misc)(
2945 thr, "pthread_barrier_init: invalid 'resizable' argument"
2946 );
2947 }
2948
2949 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2950 tl_assert(bar);
2951
2952 if (bar->initted) {
2953 HG_(record_error_Misc)(
2954 thr, "pthread_barrier_init: barrier is already initialised"
2955 );
2956 }
2957
2958 if (bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
2959 tl_assert(bar->initted);
2960 HG_(record_error_Misc)(
2961 thr, "pthread_barrier_init: threads are waiting at barrier"
2962 );
2963 VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
2964 }
2965 if (!bar->waiting) {
2966 bar->waiting = VG_(newXA)( HG_(zalloc), "hg.eHPBIP.1", HG_(free),
2967 sizeof(Thread*) );
2968 }
2969
2970 tl_assert(VG_(sizeXA)(bar->waiting) == 0);
2971 bar->initted = True;
2972 bar->resizable = resizable == 1 ? True : False;
2973 bar->size = count;
2974 }
2975
2976
evh__HG_PTHREAD_BARRIER_DESTROY_PRE(ThreadId tid,void * barrier)2977 static void evh__HG_PTHREAD_BARRIER_DESTROY_PRE ( ThreadId tid,
2978 void* barrier )
2979 {
2980 Thread* thr;
2981 Bar* bar;
2982
2983 /* Deal with destroy events. The only purpose is to free storage
2984 associated with the barrier, so as to avoid any possible
2985 resource leaks. */
2986 if (SHOW_EVENTS >= 1)
2987 VG_(printf)("evh__HG_PTHREAD_BARRIER_DESTROY_PRE"
2988 "(tid=%d, barrier=%p)\n",
2989 (Int)tid, (void*)barrier );
2990
2991 thr = map_threads_maybe_lookup( tid );
2992 tl_assert(thr); /* cannot fail - Thread* must already exist */
2993
2994 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2995 tl_assert(bar);
2996
2997 if (!bar->initted) {
2998 HG_(record_error_Misc)(
2999 thr, "pthread_barrier_destroy: barrier was never initialised"
3000 );
3001 }
3002
3003 if (bar->initted && bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
3004 HG_(record_error_Misc)(
3005 thr, "pthread_barrier_destroy: threads are waiting at barrier"
3006 );
3007 }
3008
3009 /* Maybe we shouldn't do this; just let it persist, so that when it
3010 is reinitialised we don't need to do any dynamic memory
3011 allocation? The downside is a potentially unlimited space leak,
3012 if the client creates (in turn) a large number of barriers all
3013 at different locations. Note that if we do later move to the
3014 don't-delete-it scheme, we need to mark the barrier as
3015 uninitialised again since otherwise a later _init call will
3016 elicit a duplicate-init error. */
3017 map_barrier_to_Bar_delete( barrier );
3018 }
3019
3020
3021 /* All the threads have arrived. Now do the Interesting Bit. Get a
3022 new synchronisation object and do a weak send to it from all the
3023 participating threads. This makes its vector clocks be the join of
3024 all the individual threads' vector clocks. Then do a strong
3025 receive from it back to all threads, so that their VCs are a copy
3026 of it (hence are all equal to the join of their original VCs.) */
do_barrier_cross_sync_and_empty(Bar * bar)3027 static void do_barrier_cross_sync_and_empty ( Bar* bar )
3028 {
3029 /* XXX check bar->waiting has no duplicates */
3030 UWord i;
3031 SO* so = libhb_so_alloc();
3032
3033 tl_assert(bar->waiting);
3034 tl_assert(VG_(sizeXA)(bar->waiting) == bar->size);
3035
3036 /* compute the join ... */
3037 for (i = 0; i < bar->size; i++) {
3038 Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
3039 Thr* hbthr = t->hbthr;
3040 libhb_so_send( hbthr, so, False/*weak send*/ );
3041 }
3042 /* ... and distribute to all threads */
3043 for (i = 0; i < bar->size; i++) {
3044 Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
3045 Thr* hbthr = t->hbthr;
3046 libhb_so_recv( hbthr, so, True/*strong recv*/ );
3047 }
3048
3049 /* finally, we must empty out the waiting vector */
3050 VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
3051
3052 /* and we don't need this any more. Perhaps a stack-allocated
3053 SO would be better? */
3054 libhb_so_dealloc(so);
3055 }
3056
3057
evh__HG_PTHREAD_BARRIER_WAIT_PRE(ThreadId tid,void * barrier)3058 static void evh__HG_PTHREAD_BARRIER_WAIT_PRE ( ThreadId tid,
3059 void* barrier )
3060 {
3061 /* This function gets called after a client thread calls
3062 pthread_barrier_wait but before it arrives at the real
3063 pthread_barrier_wait.
3064
3065 Why is the following correct? It's a bit subtle.
3066
3067 If this is not the last thread arriving at the barrier, we simply
3068 note its presence and return. Because valgrind (at least as of
3069 Nov 08) is single threaded, we are guaranteed safe from any race
3070 conditions when in this function -- no other client threads are
3071 running.
3072
3073 If this is the last thread, then we are again the only running
3074 thread. All the other threads will have either arrived at the
3075 real pthread_barrier_wait or are on their way to it, but in any
3076 case are guaranteed not to be able to move past it, because this
3077 thread is currently in this function and so has not yet arrived
3078 at the real pthread_barrier_wait. That means that:
3079
3080 1. While we are in this function, none of the other threads
3081 waiting at the barrier can move past it.
3082
3083 2. When this function returns (and simulated execution resumes),
3084 this thread and all other waiting threads will be able to move
3085 past the real barrier.
3086
3087 Because of this, it is now safe to update the vector clocks of
3088 all threads, to represent the fact that they all arrived at the
3089 barrier and have all moved on. There is no danger of any
3090 complications to do with some threads leaving the barrier and
3091 racing back round to the front, whilst others are still leaving
3092 (which is the primary source of complication in correct handling/
3093 implementation of barriers). That can't happen because we update
3094 here our data structures so as to indicate that the threads have
3095 passed the barrier, even though, as per (2) above, they are
3096 guaranteed not to pass the barrier until we return.
3097
3098 This relies crucially on Valgrind being single threaded. If that
3099 changes, this will need to be reconsidered.
3100 */
3101 Thread* thr;
3102 Bar* bar;
3103 UWord present;
3104
3105 if (SHOW_EVENTS >= 1)
3106 VG_(printf)("evh__HG_PTHREAD_BARRIER_WAIT_PRE"
3107 "(tid=%d, barrier=%p)\n",
3108 (Int)tid, (void*)barrier );
3109
3110 thr = map_threads_maybe_lookup( tid );
3111 tl_assert(thr); /* cannot fail - Thread* must already exist */
3112
3113 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
3114 tl_assert(bar);
3115
3116 if (!bar->initted) {
3117 HG_(record_error_Misc)(
3118 thr, "pthread_barrier_wait: barrier is uninitialised"
3119 );
3120 return; /* client is broken .. avoid assertions below */
3121 }
3122
3123 /* guaranteed by _INIT_PRE above */
3124 tl_assert(bar->size > 0);
3125 tl_assert(bar->waiting);
3126
3127 VG_(addToXA)( bar->waiting, &thr );
3128
3129 /* guaranteed by this function */
3130 present = VG_(sizeXA)(bar->waiting);
3131 tl_assert(present > 0 && present <= bar->size);
3132
3133 if (present < bar->size)
3134 return;
3135
3136 do_barrier_cross_sync_and_empty(bar);
3137 }
3138
3139
evh__HG_PTHREAD_BARRIER_RESIZE_PRE(ThreadId tid,void * barrier,UWord newcount)3140 static void evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( ThreadId tid,
3141 void* barrier,
3142 UWord newcount )
3143 {
3144 Thread* thr;
3145 Bar* bar;
3146 UWord present;
3147
3148 if (SHOW_EVENTS >= 1)
3149 VG_(printf)("evh__HG_PTHREAD_BARRIER_RESIZE_PRE"
3150 "(tid=%d, barrier=%p, newcount=%lu)\n",
3151 (Int)tid, (void*)barrier, newcount );
3152
3153 thr = map_threads_maybe_lookup( tid );
3154 tl_assert(thr); /* cannot fail - Thread* must already exist */
3155
3156 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
3157 tl_assert(bar);
3158
3159 if (!bar->initted) {
3160 HG_(record_error_Misc)(
3161 thr, "pthread_barrier_resize: barrier is uninitialised"
3162 );
3163 return; /* client is broken .. avoid assertions below */
3164 }
3165
3166 if (!bar->resizable) {
3167 HG_(record_error_Misc)(
3168 thr, "pthread_barrier_resize: barrier is may not be resized"
3169 );
3170 return; /* client is broken .. avoid assertions below */
3171 }
3172
3173 if (newcount == 0) {
3174 HG_(record_error_Misc)(
3175 thr, "pthread_barrier_resize: 'newcount' argument is zero"
3176 );
3177 return; /* client is broken .. avoid assertions below */
3178 }
3179
3180 /* guaranteed by _INIT_PRE above */
3181 tl_assert(bar->size > 0);
3182 tl_assert(bar->waiting);
3183 /* Guaranteed by this fn */
3184 tl_assert(newcount > 0);
3185
3186 if (newcount >= bar->size) {
3187 /* Increasing the capacity. There's no possibility of threads
3188 moving on from the barrier in this situation, so just note
3189 the fact and do nothing more. */
3190 bar->size = newcount;
3191 } else {
3192 /* Decreasing the capacity. If we decrease it to be equal or
3193 below the number of waiting threads, they will now move past
3194 the barrier, so need to mess with dep edges in the same way
3195 as if the barrier had filled up normally. */
3196 present = VG_(sizeXA)(bar->waiting);
3197 tl_assert(present >= 0 && present <= bar->size);
3198 if (newcount <= present) {
3199 bar->size = present; /* keep the cross_sync call happy */
3200 do_barrier_cross_sync_and_empty(bar);
3201 }
3202 bar->size = newcount;
3203 }
3204 }
3205
3206
3207 /* ----------------------------------------------------- */
3208 /* ----- events to do with user-specified HB edges ----- */
3209 /* ----------------------------------------------------- */
3210
3211 /* A mapping from arbitrary UWord tag to the SO associated with it.
3212 The UWord tags are meaningless to us, interpreted only by the
3213 user. */
3214
3215
3216
3217 /* UWord -> SO* */
3218 static WordFM* map_usertag_to_SO = NULL;
3219
map_usertag_to_SO_INIT(void)3220 static void map_usertag_to_SO_INIT ( void ) {
3221 if (UNLIKELY(map_usertag_to_SO == NULL)) {
3222 map_usertag_to_SO = VG_(newFM)( HG_(zalloc),
3223 "hg.mutS.1", HG_(free), NULL );
3224 }
3225 }
3226
map_usertag_to_SO_lookup_or_alloc(UWord usertag)3227 static SO* map_usertag_to_SO_lookup_or_alloc ( UWord usertag ) {
3228 UWord key, val;
3229 map_usertag_to_SO_INIT();
3230 if (VG_(lookupFM)( map_usertag_to_SO, &key, &val, usertag )) {
3231 tl_assert(key == (UWord)usertag);
3232 return (SO*)val;
3233 } else {
3234 SO* so = libhb_so_alloc();
3235 VG_(addToFM)( map_usertag_to_SO, usertag, (UWord)so );
3236 return so;
3237 }
3238 }
3239
map_usertag_to_SO_delete(UWord usertag)3240 static void map_usertag_to_SO_delete ( UWord usertag ) {
3241 UWord keyW, valW;
3242 map_usertag_to_SO_INIT();
3243 if (VG_(delFromFM)( map_usertag_to_SO, &keyW, &valW, usertag )) {
3244 SO* so = (SO*)valW;
3245 tl_assert(keyW == usertag);
3246 tl_assert(so);
3247 libhb_so_dealloc(so);
3248 }
3249 }
3250
3251
3252 static
evh__HG_USERSO_SEND_PRE(ThreadId tid,UWord usertag)3253 void evh__HG_USERSO_SEND_PRE ( ThreadId tid, UWord usertag )
3254 {
3255 /* TID is just about to notionally sent a message on a notional
3256 abstract synchronisation object whose identity is given by
3257 USERTAG. Bind USERTAG to a real SO if it is not already so
3258 bound, and do a 'weak send' on the SO. This joins the vector
3259 clocks from this thread into any vector clocks already present
3260 in the SO. The resulting SO vector clocks are later used by
3261 other thread(s) which successfully 'receive' from the SO,
3262 thereby acquiring a dependency on all the events that have
3263 previously signalled on this SO. */
3264 Thread* thr;
3265 SO* so;
3266
3267 if (SHOW_EVENTS >= 1)
3268 VG_(printf)("evh__HG_USERSO_SEND_PRE(ctid=%d, usertag=%#lx)\n",
3269 (Int)tid, usertag );
3270
3271 thr = map_threads_maybe_lookup( tid );
3272 tl_assert(thr); /* cannot fail - Thread* must already exist */
3273
3274 so = map_usertag_to_SO_lookup_or_alloc( usertag );
3275 tl_assert(so);
3276
3277 libhb_so_send( thr->hbthr, so, False/*!strong_send*/ );
3278 }
3279
3280 static
evh__HG_USERSO_RECV_POST(ThreadId tid,UWord usertag)3281 void evh__HG_USERSO_RECV_POST ( ThreadId tid, UWord usertag )
3282 {
3283 /* TID has just notionally received a message from a notional
3284 abstract synchronisation object whose identity is given by
3285 USERTAG. Bind USERTAG to a real SO if it is not already so
3286 bound. If the SO has at some point in the past been 'sent' on,
3287 to a 'strong receive' on it, thereby acquiring a dependency on
3288 the sender. */
3289 Thread* thr;
3290 SO* so;
3291
3292 if (SHOW_EVENTS >= 1)
3293 VG_(printf)("evh__HG_USERSO_RECV_POST(ctid=%d, usertag=%#lx)\n",
3294 (Int)tid, usertag );
3295
3296 thr = map_threads_maybe_lookup( tid );
3297 tl_assert(thr); /* cannot fail - Thread* must already exist */
3298
3299 so = map_usertag_to_SO_lookup_or_alloc( usertag );
3300 tl_assert(so);
3301
3302 /* Acquire a dependency on it. If the SO has never so far been
3303 sent on, then libhb_so_recv will do nothing. So we're safe
3304 regardless of SO's history. */
3305 libhb_so_recv( thr->hbthr, so, True/*strong_recv*/ );
3306 }
3307
3308 static
evh__HG_USERSO_FORGET_ALL(ThreadId tid,UWord usertag)3309 void evh__HG_USERSO_FORGET_ALL ( ThreadId tid, UWord usertag )
3310 {
3311 /* TID declares that any happens-before edges notionally stored in
3312 USERTAG can be deleted. If (as would normally be the case) a
3313 SO is associated with USERTAG, then the assocation is removed
3314 and all resources associated with SO are freed. Importantly,
3315 that frees up any VTSs stored in SO. */
3316 if (SHOW_EVENTS >= 1)
3317 VG_(printf)("evh__HG_USERSO_FORGET_ALL(ctid=%d, usertag=%#lx)\n",
3318 (Int)tid, usertag );
3319
3320 map_usertag_to_SO_delete( usertag );
3321 }
3322
3323
3324 /*--------------------------------------------------------------*/
3325 /*--- Lock acquisition order monitoring ---*/
3326 /*--------------------------------------------------------------*/
3327
3328 /* FIXME: here are some optimisations still to do in
3329 laog__pre_thread_acquires_lock.
3330
3331 The graph is structured so that if L1 --*--> L2 then L1 must be
3332 acquired before L2.
3333
3334 The common case is that some thread T holds (eg) L1 L2 and L3 and
3335 is repeatedly acquiring and releasing Ln, and there is no ordering
3336 error in what it is doing. Hence it repeatly:
3337
3338 (1) searches laog to see if Ln --*--> {L1,L2,L3}, which always
3339 produces the answer No (because there is no error).
3340
3341 (2) adds edges {L1,L2,L3} --> Ln to laog, which are already present
3342 (because they already got added the first time T acquired Ln).
3343
3344 Hence cache these two events:
3345
3346 (1) Cache result of the query from last time. Invalidate the cache
3347 any time any edges are added to or deleted from laog.
3348
3349 (2) Cache these add-edge requests and ignore them if said edges
3350 have already been added to laog. Invalidate the cache any time
3351 any edges are deleted from laog.
3352 */
3353
3354 typedef
3355 struct {
3356 WordSetID inns; /* in univ_laog */
3357 WordSetID outs; /* in univ_laog */
3358 }
3359 LAOGLinks;
3360
3361 /* lock order acquisition graph */
3362 static WordFM* laog = NULL; /* WordFM Lock* LAOGLinks* */
3363
3364 /* EXPOSITION ONLY: for each edge in 'laog', record the two places
3365 where that edge was created, so that we can show the user later if
3366 we need to. */
3367 typedef
3368 struct {
3369 Addr src_ga; /* Lock guest addresses for */
3370 Addr dst_ga; /* src/dst of the edge */
3371 ExeContext* src_ec; /* And corresponding places where that */
3372 ExeContext* dst_ec; /* ordering was established */
3373 }
3374 LAOGLinkExposition;
3375
cmp_LAOGLinkExposition(UWord llx1W,UWord llx2W)3376 static Word cmp_LAOGLinkExposition ( UWord llx1W, UWord llx2W ) {
3377 /* Compare LAOGLinkExposition*s by (src_ga,dst_ga) field pair. */
3378 LAOGLinkExposition* llx1 = (LAOGLinkExposition*)llx1W;
3379 LAOGLinkExposition* llx2 = (LAOGLinkExposition*)llx2W;
3380 if (llx1->src_ga < llx2->src_ga) return -1;
3381 if (llx1->src_ga > llx2->src_ga) return 1;
3382 if (llx1->dst_ga < llx2->dst_ga) return -1;
3383 if (llx1->dst_ga > llx2->dst_ga) return 1;
3384 return 0;
3385 }
3386
3387 static WordFM* laog_exposition = NULL; /* WordFM LAOGLinkExposition* NULL */
3388 /* end EXPOSITION ONLY */
3389
3390
3391 __attribute__((noinline))
laog__init(void)3392 static void laog__init ( void )
3393 {
3394 tl_assert(!laog);
3395 tl_assert(!laog_exposition);
3396 tl_assert(HG_(clo_track_lockorders));
3397
3398 laog = VG_(newFM)( HG_(zalloc), "hg.laog__init.1",
3399 HG_(free), NULL/*unboxedcmp*/ );
3400
3401 laog_exposition = VG_(newFM)( HG_(zalloc), "hg.laog__init.2", HG_(free),
3402 cmp_LAOGLinkExposition );
3403 }
3404
laog__show(const HChar * who)3405 static void laog__show ( const HChar* who ) {
3406 UWord i, ws_size;
3407 UWord* ws_words;
3408 Lock* me;
3409 LAOGLinks* links;
3410 VG_(printf)("laog (requested by %s) {\n", who);
3411 VG_(initIterFM)( laog );
3412 me = NULL;
3413 links = NULL;
3414 while (VG_(nextIterFM)( laog, (UWord*)&me,
3415 (UWord*)&links )) {
3416 tl_assert(me);
3417 tl_assert(links);
3418 VG_(printf)(" node %p:\n", me);
3419 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3420 for (i = 0; i < ws_size; i++)
3421 VG_(printf)(" inn %#lx\n", ws_words[i] );
3422 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3423 for (i = 0; i < ws_size; i++)
3424 VG_(printf)(" out %#lx\n", ws_words[i] );
3425 me = NULL;
3426 links = NULL;
3427 }
3428 VG_(doneIterFM)( laog );
3429 VG_(printf)("}\n");
3430 }
3431
univ_laog_do_GC(void)3432 static void univ_laog_do_GC ( void ) {
3433 Word i;
3434 LAOGLinks* links;
3435 Word seen = 0;
3436 Int prev_next_gc_univ_laog = next_gc_univ_laog;
3437 const UWord univ_laog_cardinality = HG_(cardinalityWSU)( univ_laog);
3438
3439 Bool *univ_laog_seen = HG_(zalloc) ( "hg.gc_univ_laog.1",
3440 (Int) univ_laog_cardinality
3441 * sizeof(Bool) );
3442 // univ_laog_seen[*] set to 0 (False) by zalloc.
3443
3444 VG_(initIterFM)( laog );
3445 links = NULL;
3446 while (VG_(nextIterFM)( laog, NULL, (UWord*)&links )) {
3447 tl_assert(links);
3448 tl_assert(links->inns >= 0 && links->inns < univ_laog_cardinality);
3449 univ_laog_seen[links->inns] = True;
3450 tl_assert(links->outs >= 0 && links->outs < univ_laog_cardinality);
3451 univ_laog_seen[links->outs] = True;
3452 links = NULL;
3453 }
3454 VG_(doneIterFM)( laog );
3455
3456 for (i = 0; i < (Int)univ_laog_cardinality; i++) {
3457 if (univ_laog_seen[i])
3458 seen++;
3459 else
3460 HG_(dieWS) ( univ_laog, (WordSet)i );
3461 }
3462
3463 HG_(free) (univ_laog_seen);
3464
3465 // We need to decide the value of the next_gc.
3466 // 3 solutions were looked at:
3467 // Sol 1: garbage collect at seen * 2
3468 // This solution was a lot slower, probably because we both do a lot of
3469 // garbage collection and do not keep long enough laog WV that will become
3470 // useful again very soon.
3471 // Sol 2: garbage collect at a percentage increase of the current cardinality
3472 // (with a min increase of 1)
3473 // Trials on a small test program with 1%, 5% and 10% increase was done.
3474 // 1% is slightly faster than 5%, which is slightly slower than 10%.
3475 // However, on a big application, this caused the memory to be exhausted,
3476 // as even a 1% increase of size at each gc becomes a lot, when many gc
3477 // are done.
3478 // Sol 3: always garbage collect at current cardinality + 1.
3479 // This solution was the fastest of the 3 solutions, and caused no memory
3480 // exhaustion in the big application.
3481 //
3482 // With regards to cost introduced by gc: on the t2t perf test (doing only
3483 // lock/unlock operations), t2t 50 10 2 was about 25% faster than the
3484 // version with garbage collection. With t2t 50 20 2, my machine started
3485 // to page out, and so the garbage collected version was much faster.
3486 // On smaller lock sets (e.g. t2t 20 5 2, giving about 100 locks), the
3487 // difference performance is insignificant (~ 0.1 s).
3488 // Of course, it might be that real life programs are not well represented
3489 // by t2t.
3490
3491 // If ever we want to have a more sophisticated control
3492 // (e.g. clo options to control the percentage increase or fixed increased),
3493 // we should do it here, eg.
3494 // next_gc_univ_laog = prev_next_gc_univ_laog + VG_(clo_laog_gc_fixed);
3495 // Currently, we just hard-code the solution 3 above.
3496 next_gc_univ_laog = prev_next_gc_univ_laog + 1;
3497
3498 if (VG_(clo_stats))
3499 VG_(message)
3500 (Vg_DebugMsg,
3501 "univ_laog_do_GC cardinality entered %d exit %d next gc at %d\n",
3502 (Int)univ_laog_cardinality, (Int)seen, next_gc_univ_laog);
3503 }
3504
3505
3506 __attribute__((noinline))
laog__add_edge(Lock * src,Lock * dst)3507 static void laog__add_edge ( Lock* src, Lock* dst ) {
3508 UWord keyW;
3509 LAOGLinks* links;
3510 Bool presentF, presentR;
3511 if (0) VG_(printf)("laog__add_edge %p %p\n", src, dst);
3512
3513 /* Take the opportunity to sanity check the graph. Record in
3514 presentF if there is already a src->dst mapping in this node's
3515 forwards links, and presentR if there is already a src->dst
3516 mapping in this node's backwards links. They should agree!
3517 Also, we need to know whether the edge was already present so as
3518 to decide whether or not to update the link details mapping. We
3519 can compute presentF and presentR essentially for free, so may
3520 as well do this always. */
3521 presentF = presentR = False;
3522
3523 /* Update the out edges for src */
3524 keyW = 0;
3525 links = NULL;
3526 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)src )) {
3527 WordSetID outs_new;
3528 tl_assert(links);
3529 tl_assert(keyW == (UWord)src);
3530 outs_new = HG_(addToWS)( univ_laog, links->outs, (UWord)dst );
3531 presentF = outs_new == links->outs;
3532 links->outs = outs_new;
3533 } else {
3534 links = HG_(zalloc)("hg.lae.1", sizeof(LAOGLinks));
3535 links->inns = HG_(emptyWS)( univ_laog );
3536 links->outs = HG_(singletonWS)( univ_laog, (UWord)dst );
3537 VG_(addToFM)( laog, (UWord)src, (UWord)links );
3538 }
3539 /* Update the in edges for dst */
3540 keyW = 0;
3541 links = NULL;
3542 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)dst )) {
3543 WordSetID inns_new;
3544 tl_assert(links);
3545 tl_assert(keyW == (UWord)dst);
3546 inns_new = HG_(addToWS)( univ_laog, links->inns, (UWord)src );
3547 presentR = inns_new == links->inns;
3548 links->inns = inns_new;
3549 } else {
3550 links = HG_(zalloc)("hg.lae.2", sizeof(LAOGLinks));
3551 links->inns = HG_(singletonWS)( univ_laog, (UWord)src );
3552 links->outs = HG_(emptyWS)( univ_laog );
3553 VG_(addToFM)( laog, (UWord)dst, (UWord)links );
3554 }
3555
3556 tl_assert( (presentF && presentR) || (!presentF && !presentR) );
3557
3558 if (!presentF && src->acquired_at && dst->acquired_at) {
3559 LAOGLinkExposition expo;
3560 /* If this edge is entering the graph, and we have acquired_at
3561 information for both src and dst, record those acquisition
3562 points. Hence, if there is later a violation of this
3563 ordering, we can show the user the two places in which the
3564 required src-dst ordering was previously established. */
3565 if (0) VG_(printf)("acquire edge %#lx %#lx\n",
3566 src->guestaddr, dst->guestaddr);
3567 expo.src_ga = src->guestaddr;
3568 expo.dst_ga = dst->guestaddr;
3569 expo.src_ec = NULL;
3570 expo.dst_ec = NULL;
3571 tl_assert(laog_exposition);
3572 if (VG_(lookupFM)( laog_exposition, NULL, NULL, (UWord)&expo )) {
3573 /* we already have it; do nothing */
3574 } else {
3575 LAOGLinkExposition* expo2 = HG_(zalloc)("hg.lae.3",
3576 sizeof(LAOGLinkExposition));
3577 expo2->src_ga = src->guestaddr;
3578 expo2->dst_ga = dst->guestaddr;
3579 expo2->src_ec = src->acquired_at;
3580 expo2->dst_ec = dst->acquired_at;
3581 VG_(addToFM)( laog_exposition, (UWord)expo2, (UWord)NULL );
3582 }
3583 }
3584
3585 if (HG_(cardinalityWSU) (univ_laog) >= next_gc_univ_laog)
3586 univ_laog_do_GC();
3587 }
3588
3589 __attribute__((noinline))
laog__del_edge(Lock * src,Lock * dst)3590 static void laog__del_edge ( Lock* src, Lock* dst ) {
3591 UWord keyW;
3592 LAOGLinks* links;
3593 if (0) VG_(printf)("laog__del_edge enter %p %p\n", src, dst);
3594 /* Update the out edges for src */
3595 keyW = 0;
3596 links = NULL;
3597 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)src )) {
3598 tl_assert(links);
3599 tl_assert(keyW == (UWord)src);
3600 links->outs = HG_(delFromWS)( univ_laog, links->outs, (UWord)dst );
3601 }
3602 /* Update the in edges for dst */
3603 keyW = 0;
3604 links = NULL;
3605 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)dst )) {
3606 tl_assert(links);
3607 tl_assert(keyW == (UWord)dst);
3608 links->inns = HG_(delFromWS)( univ_laog, links->inns, (UWord)src );
3609 }
3610
3611 /* Remove the exposition of src,dst (if present) */
3612 {
3613 LAOGLinkExposition *fm_expo;
3614
3615 LAOGLinkExposition expo;
3616 expo.src_ga = src->guestaddr;
3617 expo.dst_ga = dst->guestaddr;
3618 expo.src_ec = NULL;
3619 expo.dst_ec = NULL;
3620
3621 if (VG_(delFromFM) (laog_exposition,
3622 (UWord*)&fm_expo, NULL, (UWord)&expo )) {
3623 HG_(free) (fm_expo);
3624 }
3625 }
3626
3627 /* deleting edges can increase nr of of WS so check for gc. */
3628 if (HG_(cardinalityWSU) (univ_laog) >= next_gc_univ_laog)
3629 univ_laog_do_GC();
3630 if (0) VG_(printf)("laog__del_edge exit\n");
3631 }
3632
3633 __attribute__((noinline))
laog__succs(Lock * lk)3634 static WordSetID /* in univ_laog */ laog__succs ( Lock* lk ) {
3635 UWord keyW;
3636 LAOGLinks* links;
3637 keyW = 0;
3638 links = NULL;
3639 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)lk )) {
3640 tl_assert(links);
3641 tl_assert(keyW == (UWord)lk);
3642 return links->outs;
3643 } else {
3644 return HG_(emptyWS)( univ_laog );
3645 }
3646 }
3647
3648 __attribute__((noinline))
laog__preds(Lock * lk)3649 static WordSetID /* in univ_laog */ laog__preds ( Lock* lk ) {
3650 UWord keyW;
3651 LAOGLinks* links;
3652 keyW = 0;
3653 links = NULL;
3654 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)lk )) {
3655 tl_assert(links);
3656 tl_assert(keyW == (UWord)lk);
3657 return links->inns;
3658 } else {
3659 return HG_(emptyWS)( univ_laog );
3660 }
3661 }
3662
3663 __attribute__((noinline))
laog__sanity_check(const HChar * who)3664 static void laog__sanity_check ( const HChar* who ) {
3665 UWord i, ws_size;
3666 UWord* ws_words;
3667 Lock* me;
3668 LAOGLinks* links;
3669 VG_(initIterFM)( laog );
3670 me = NULL;
3671 links = NULL;
3672 if (0) VG_(printf)("laog sanity check\n");
3673 while (VG_(nextIterFM)( laog, (UWord*)&me,
3674 (UWord*)&links )) {
3675 tl_assert(me);
3676 tl_assert(links);
3677 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3678 for (i = 0; i < ws_size; i++) {
3679 if ( ! HG_(elemWS)( univ_laog,
3680 laog__succs( (Lock*)ws_words[i] ),
3681 (UWord)me ))
3682 goto bad;
3683 }
3684 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3685 for (i = 0; i < ws_size; i++) {
3686 if ( ! HG_(elemWS)( univ_laog,
3687 laog__preds( (Lock*)ws_words[i] ),
3688 (UWord)me ))
3689 goto bad;
3690 }
3691 me = NULL;
3692 links = NULL;
3693 }
3694 VG_(doneIterFM)( laog );
3695 return;
3696
3697 bad:
3698 VG_(printf)("laog__sanity_check(%s) FAILED\n", who);
3699 laog__show(who);
3700 tl_assert(0);
3701 }
3702
3703 /* If there is a path in laog from 'src' to any of the elements in
3704 'dst', return an arbitrarily chosen element of 'dst' reachable from
3705 'src'. If no path exist from 'src' to any element in 'dst', return
3706 NULL. */
3707 __attribute__((noinline))
3708 static
laog__do_dfs_from_to(Lock * src,WordSetID dsts)3709 Lock* laog__do_dfs_from_to ( Lock* src, WordSetID dsts /* univ_lsets */ )
3710 {
3711 Lock* ret;
3712 Word ssz;
3713 XArray* stack; /* of Lock* */
3714 WordFM* visited; /* Lock* -> void, iow, Set(Lock*) */
3715 Lock* here;
3716 WordSetID succs;
3717 UWord succs_size, i;
3718 UWord* succs_words;
3719 //laog__sanity_check();
3720
3721 /* If the destination set is empty, we can never get there from
3722 'src' :-), so don't bother to try */
3723 if (HG_(isEmptyWS)( univ_lsets, dsts ))
3724 return NULL;
3725
3726 ret = NULL;
3727 stack = VG_(newXA)( HG_(zalloc), "hg.lddft.1", HG_(free), sizeof(Lock*) );
3728 visited = VG_(newFM)( HG_(zalloc), "hg.lddft.2", HG_(free), NULL/*unboxedcmp*/ );
3729
3730 (void) VG_(addToXA)( stack, &src );
3731
3732 while (True) {
3733
3734 ssz = VG_(sizeXA)( stack );
3735
3736 if (ssz == 0) { ret = NULL; break; }
3737
3738 here = *(Lock**) VG_(indexXA)( stack, ssz-1 );
3739 VG_(dropTailXA)( stack, 1 );
3740
3741 if (HG_(elemWS)( univ_lsets, dsts, (UWord)here )) { ret = here; break; }
3742
3743 if (VG_(lookupFM)( visited, NULL, NULL, (UWord)here ))
3744 continue;
3745
3746 VG_(addToFM)( visited, (UWord)here, 0 );
3747
3748 succs = laog__succs( here );
3749 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3750 for (i = 0; i < succs_size; i++)
3751 (void) VG_(addToXA)( stack, &succs_words[i] );
3752 }
3753
3754 VG_(deleteFM)( visited, NULL, NULL );
3755 VG_(deleteXA)( stack );
3756 return ret;
3757 }
3758
3759
3760 /* Thread 'thr' is acquiring 'lk'. Check for inconsistent ordering
3761 between 'lk' and the locks already held by 'thr' and issue a
3762 complaint if so. Also, update the ordering graph appropriately.
3763 */
3764 __attribute__((noinline))
laog__pre_thread_acquires_lock(Thread * thr,Lock * lk)3765 static void laog__pre_thread_acquires_lock (
3766 Thread* thr, /* NB: BEFORE lock is added */
3767 Lock* lk
3768 )
3769 {
3770 UWord* ls_words;
3771 UWord ls_size, i;
3772 Lock* other;
3773
3774 /* It may be that 'thr' already holds 'lk' and is recursively
3775 relocking in. In this case we just ignore the call. */
3776 /* NB: univ_lsets really is correct here */
3777 if (HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lk ))
3778 return;
3779
3780 /* First, the check. Complain if there is any path in laog from lk
3781 to any of the locks already held by thr, since if any such path
3782 existed, it would mean that previously lk was acquired before
3783 (rather than after, as we are doing here) at least one of those
3784 locks.
3785 */
3786 other = laog__do_dfs_from_to(lk, thr->locksetA);
3787 if (other) {
3788 LAOGLinkExposition key, *found;
3789 /* So we managed to find a path lk --*--> other in the graph,
3790 which implies that 'lk' should have been acquired before
3791 'other' but is in fact being acquired afterwards. We present
3792 the lk/other arguments to record_error_LockOrder in the order
3793 in which they should have been acquired. */
3794 /* Go look in the laog_exposition mapping, to find the allocation
3795 points for this edge, so we can show the user. */
3796 key.src_ga = lk->guestaddr;
3797 key.dst_ga = other->guestaddr;
3798 key.src_ec = NULL;
3799 key.dst_ec = NULL;
3800 found = NULL;
3801 if (VG_(lookupFM)( laog_exposition,
3802 (UWord*)&found, NULL, (UWord)&key )) {
3803 tl_assert(found != &key);
3804 tl_assert(found->src_ga == key.src_ga);
3805 tl_assert(found->dst_ga == key.dst_ga);
3806 tl_assert(found->src_ec);
3807 tl_assert(found->dst_ec);
3808 HG_(record_error_LockOrder)(
3809 thr, lk, other,
3810 found->src_ec, found->dst_ec, other->acquired_at );
3811 } else {
3812 /* Hmm. This can't happen (can it?) */
3813 /* Yes, it can happen: see tests/tc14_laog_dinphils.
3814 Imagine we have 3 philosophers A B C, and the forks
3815 between them:
3816
3817 C
3818
3819 fCA fBC
3820
3821 A fAB B
3822
3823 Let's have the following actions:
3824 A takes fCA,fAB
3825 A releases fCA,fAB
3826 B takes fAB,fBC
3827 B releases fAB,fBC
3828 C takes fBC,fCA
3829 C releases fBC,fCA
3830
3831 Helgrind will report a lock order error when C takes fCA.
3832 Effectively, we have a deadlock if the following
3833 sequence is done:
3834 A takes fCA
3835 B takes fAB
3836 C takes fBC
3837
3838 The error reported is:
3839 Observed (incorrect) order fBC followed by fCA
3840 but the stack traces that have established the required order
3841 are not given.
3842
3843 This is because there is no pair (fCA, fBC) in laog exposition :
3844 the laog_exposition records all pairs of locks between a new lock
3845 taken by a thread and all the already taken locks.
3846 So, there is no laog_exposition (fCA, fBC) as no thread ever
3847 first locked fCA followed by fBC.
3848
3849 In other words, when the deadlock cycle involves more than
3850 two locks, then helgrind does not report the sequence of
3851 operations that created the cycle.
3852
3853 However, we can report the current stack trace (where
3854 lk is being taken), and the stack trace where other was acquired:
3855 Effectively, the variable 'other' contains a lock currently
3856 held by this thread, with its 'acquired_at'. */
3857
3858 HG_(record_error_LockOrder)(
3859 thr, lk, other,
3860 NULL, NULL, other->acquired_at );
3861 }
3862 }
3863
3864 /* Second, add to laog the pairs
3865 (old, lk) | old <- locks already held by thr
3866 Since both old and lk are currently held by thr, their acquired_at
3867 fields must be non-NULL.
3868 */
3869 tl_assert(lk->acquired_at);
3870 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, thr->locksetA );
3871 for (i = 0; i < ls_size; i++) {
3872 Lock* old = (Lock*)ls_words[i];
3873 tl_assert(old->acquired_at);
3874 laog__add_edge( old, lk );
3875 }
3876
3877 /* Why "except_Locks" ? We're here because a lock is being
3878 acquired by a thread, and we're in an inconsistent state here.
3879 See the call points in evhH__post_thread_{r,w}_acquires_lock.
3880 When called in this inconsistent state, locks__sanity_check duly
3881 barfs. */
3882 if (HG_(clo_sanity_flags) & SCE_LAOG)
3883 all_except_Locks__sanity_check("laog__pre_thread_acquires_lock-post");
3884 }
3885
3886 /* Allocates a duplicate of words. Caller must HG_(free) the result. */
UWordV_dup(UWord * words,Word words_size)3887 static UWord* UWordV_dup(UWord* words, Word words_size)
3888 {
3889 UInt i;
3890
3891 if (words_size == 0)
3892 return NULL;
3893
3894 UWord *dup = HG_(zalloc) ("hg.dup.1", (SizeT) words_size * sizeof(UWord));
3895
3896 for (i = 0; i < words_size; i++)
3897 dup[i] = words[i];
3898
3899 return dup;
3900 }
3901
3902 /* Delete from 'laog' any pair mentioning a lock in locksToDelete */
3903
3904 __attribute__((noinline))
laog__handle_one_lock_deletion(Lock * lk)3905 static void laog__handle_one_lock_deletion ( Lock* lk )
3906 {
3907 WordSetID preds, succs;
3908 UWord preds_size, succs_size, i, j;
3909 UWord *preds_words, *succs_words;
3910
3911 preds = laog__preds( lk );
3912 succs = laog__succs( lk );
3913
3914 // We need to duplicate the payload, as these can be garbage collected
3915 // during the del/add operations below.
3916 HG_(getPayloadWS)( &preds_words, &preds_size, univ_laog, preds );
3917 preds_words = UWordV_dup(preds_words, preds_size);
3918
3919 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3920 succs_words = UWordV_dup(succs_words, succs_size);
3921
3922 for (i = 0; i < preds_size; i++)
3923 laog__del_edge( (Lock*)preds_words[i], lk );
3924
3925 for (j = 0; j < succs_size; j++)
3926 laog__del_edge( lk, (Lock*)succs_words[j] );
3927
3928 for (i = 0; i < preds_size; i++) {
3929 for (j = 0; j < succs_size; j++) {
3930 if (preds_words[i] != succs_words[j]) {
3931 /* This can pass unlocked locks to laog__add_edge, since
3932 we're deleting stuff. So their acquired_at fields may
3933 be NULL. */
3934 laog__add_edge( (Lock*)preds_words[i], (Lock*)succs_words[j] );
3935 }
3936 }
3937 }
3938
3939 if (preds_words)
3940 HG_(free) (preds_words);
3941 if (succs_words)
3942 HG_(free) (succs_words);
3943
3944 // Remove lk information from laog links FM
3945 {
3946 LAOGLinks *links;
3947 Lock* linked_lk;
3948
3949 if (VG_(delFromFM) (laog,
3950 (UWord*)&linked_lk, (UWord*)&links, (UWord)lk)) {
3951 tl_assert (linked_lk == lk);
3952 HG_(free) (links);
3953 }
3954 }
3955 /* FIXME ??? What about removing lock lk data from EXPOSITION ??? */
3956 }
3957
3958 //__attribute__((noinline))
3959 //static void laog__handle_lock_deletions (
3960 // WordSetID /* in univ_laog */ locksToDelete
3961 // )
3962 //{
3963 // Word i, ws_size;
3964 // UWord* ws_words;
3965 //
3966 //
3967 // HG_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, locksToDelete );
3968 // UWordV_dup call needed here ...
3969 // for (i = 0; i < ws_size; i++)
3970 // laog__handle_one_lock_deletion( (Lock*)ws_words[i] );
3971 //
3972 // if (HG_(clo_sanity_flags) & SCE_LAOG)
3973 // all__sanity_check("laog__handle_lock_deletions-post");
3974 //}
3975
3976
3977 /*--------------------------------------------------------------*/
3978 /*--- Malloc/free replacements ---*/
3979 /*--------------------------------------------------------------*/
3980
3981 typedef
3982 struct {
3983 void* next; /* required by m_hashtable */
3984 Addr payload; /* ptr to actual block */
3985 SizeT szB; /* size requested */
3986 ExeContext* where; /* where it was allocated */
3987 Thread* thr; /* allocating thread */
3988 }
3989 MallocMeta;
3990
3991 /* A hash table of MallocMetas, used to track malloc'd blocks
3992 (obviously). */
3993 static VgHashTable *hg_mallocmeta_table = NULL;
3994
3995 /* MallocMeta are small elements. We use a pool to avoid
3996 the overhead of malloc for each MallocMeta. */
3997 static PoolAlloc *MallocMeta_poolalloc = NULL;
3998
new_MallocMeta(void)3999 static MallocMeta* new_MallocMeta ( void ) {
4000 MallocMeta* md = VG_(allocEltPA) (MallocMeta_poolalloc);
4001 VG_(memset)(md, 0, sizeof(MallocMeta));
4002 return md;
4003 }
delete_MallocMeta(MallocMeta * md)4004 static void delete_MallocMeta ( MallocMeta* md ) {
4005 VG_(freeEltPA)(MallocMeta_poolalloc, md);
4006 }
4007
4008
4009 /* Allocate a client block and set up the metadata for it. */
4010
4011 static
handle_alloc(ThreadId tid,SizeT szB,SizeT alignB,Bool is_zeroed)4012 void* handle_alloc ( ThreadId tid,
4013 SizeT szB, SizeT alignB, Bool is_zeroed )
4014 {
4015 Addr p;
4016 MallocMeta* md;
4017
4018 tl_assert( ((SSizeT)szB) >= 0 );
4019 p = (Addr)VG_(cli_malloc)(alignB, szB);
4020 if (!p) {
4021 return NULL;
4022 }
4023 if (is_zeroed)
4024 VG_(memset)((void*)p, 0, szB);
4025
4026 /* Note that map_threads_lookup must succeed (cannot assert), since
4027 memory can only be allocated by currently alive threads, hence
4028 they must have an entry in map_threads. */
4029 md = new_MallocMeta();
4030 md->payload = p;
4031 md->szB = szB;
4032 md->where = VG_(record_ExeContext)( tid, 0 );
4033 md->thr = map_threads_lookup( tid );
4034
4035 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md );
4036
4037 /* Tell the lower level memory wranglers. */
4038 evh__new_mem_heap( p, szB, is_zeroed );
4039
4040 return (void*)p;
4041 }
4042
4043 /* Re the checks for less-than-zero (also in hg_cli__realloc below):
4044 Cast to a signed type to catch any unexpectedly negative args.
4045 We're assuming here that the size asked for is not greater than
4046 2^31 bytes (for 32-bit platforms) or 2^63 bytes (for 64-bit
4047 platforms). */
hg_cli__malloc(ThreadId tid,SizeT n)4048 static void* hg_cli__malloc ( ThreadId tid, SizeT n ) {
4049 if (((SSizeT)n) < 0) return NULL;
4050 return handle_alloc ( tid, n, VG_(clo_alignment),
4051 /*is_zeroed*/False );
4052 }
hg_cli____builtin_new(ThreadId tid,SizeT n)4053 static void* hg_cli____builtin_new ( ThreadId tid, SizeT n ) {
4054 if (((SSizeT)n) < 0) return NULL;
4055 return handle_alloc ( tid, n, VG_(clo_alignment),
4056 /*is_zeroed*/False );
4057 }
hg_cli____builtin_vec_new(ThreadId tid,SizeT n)4058 static void* hg_cli____builtin_vec_new ( ThreadId tid, SizeT n ) {
4059 if (((SSizeT)n) < 0) return NULL;
4060 return handle_alloc ( tid, n, VG_(clo_alignment),
4061 /*is_zeroed*/False );
4062 }
hg_cli__memalign(ThreadId tid,SizeT align,SizeT n)4063 static void* hg_cli__memalign ( ThreadId tid, SizeT align, SizeT n ) {
4064 if (((SSizeT)n) < 0) return NULL;
4065 return handle_alloc ( tid, n, align,
4066 /*is_zeroed*/False );
4067 }
hg_cli__calloc(ThreadId tid,SizeT nmemb,SizeT size1)4068 static void* hg_cli__calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) {
4069 if ( ((SSizeT)nmemb) < 0 || ((SSizeT)size1) < 0 ) return NULL;
4070 return handle_alloc ( tid, nmemb*size1, VG_(clo_alignment),
4071 /*is_zeroed*/True );
4072 }
4073
4074
4075 /* Free a client block, including getting rid of the relevant
4076 metadata. */
4077
handle_free(ThreadId tid,void * p)4078 static void handle_free ( ThreadId tid, void* p )
4079 {
4080 MallocMeta *md, *old_md;
4081 SizeT szB;
4082
4083 /* First see if we can find the metadata for 'p'. */
4084 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
4085 if (!md)
4086 return; /* apparently freeing a bogus address. Oh well. */
4087
4088 tl_assert(md->payload == (Addr)p);
4089 szB = md->szB;
4090
4091 /* Nuke the metadata block */
4092 old_md = (MallocMeta*)
4093 VG_(HT_remove)( hg_mallocmeta_table, (UWord)p );
4094 tl_assert(old_md); /* it must be present - we just found it */
4095 tl_assert(old_md == md);
4096 tl_assert(old_md->payload == (Addr)p);
4097
4098 VG_(cli_free)((void*)old_md->payload);
4099 delete_MallocMeta(old_md);
4100
4101 /* Tell the lower level memory wranglers. */
4102 evh__die_mem_heap( (Addr)p, szB );
4103 }
4104
hg_cli__free(ThreadId tid,void * p)4105 static void hg_cli__free ( ThreadId tid, void* p ) {
4106 handle_free(tid, p);
4107 }
hg_cli____builtin_delete(ThreadId tid,void * p)4108 static void hg_cli____builtin_delete ( ThreadId tid, void* p ) {
4109 handle_free(tid, p);
4110 }
hg_cli____builtin_vec_delete(ThreadId tid,void * p)4111 static void hg_cli____builtin_vec_delete ( ThreadId tid, void* p ) {
4112 handle_free(tid, p);
4113 }
4114
4115
hg_cli__realloc(ThreadId tid,void * payloadV,SizeT new_size)4116 static void* hg_cli__realloc ( ThreadId tid, void* payloadV, SizeT new_size )
4117 {
4118 MallocMeta *md, *md_new, *md_tmp;
4119 SizeT i;
4120
4121 Addr payload = (Addr)payloadV;
4122
4123 if (((SSizeT)new_size) < 0) return NULL;
4124
4125 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)payload );
4126 if (!md)
4127 return NULL; /* apparently realloc-ing a bogus address. Oh well. */
4128
4129 tl_assert(md->payload == payload);
4130
4131 if (md->szB == new_size) {
4132 /* size unchanged */
4133 md->where = VG_(record_ExeContext)(tid, 0);
4134 return payloadV;
4135 }
4136
4137 if (md->szB > new_size) {
4138 /* new size is smaller */
4139 md->szB = new_size;
4140 md->where = VG_(record_ExeContext)(tid, 0);
4141 evh__die_mem_heap( md->payload + new_size, md->szB - new_size );
4142 return payloadV;
4143 }
4144
4145 /* else */ {
4146 /* new size is bigger */
4147 Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
4148
4149 /* First half kept and copied, second half new */
4150 // FIXME: shouldn't we use a copier which implements the
4151 // memory state machine?
4152 evh__copy_mem( payload, p_new, md->szB );
4153 evh__new_mem_heap ( p_new + md->szB, new_size - md->szB,
4154 /*inited*/False );
4155 /* FIXME: can anything funny happen here? specifically, if the
4156 old range contained a lock, then die_mem_heap will complain.
4157 Is that the correct behaviour? Not sure. */
4158 evh__die_mem_heap( payload, md->szB );
4159
4160 /* Copy from old to new */
4161 for (i = 0; i < md->szB; i++)
4162 ((UChar*)p_new)[i] = ((UChar*)payload)[i];
4163
4164 /* Because the metadata hash table is index by payload address,
4165 we have to get rid of the old hash table entry and make a new
4166 one. We can't just modify the existing metadata in place,
4167 because then it would (almost certainly) be in the wrong hash
4168 chain. */
4169 md_new = new_MallocMeta();
4170 *md_new = *md;
4171
4172 md_tmp = VG_(HT_remove)( hg_mallocmeta_table, payload );
4173 tl_assert(md_tmp);
4174 tl_assert(md_tmp == md);
4175
4176 VG_(cli_free)((void*)md->payload);
4177 delete_MallocMeta(md);
4178
4179 /* Update fields */
4180 md_new->where = VG_(record_ExeContext)( tid, 0 );
4181 md_new->szB = new_size;
4182 md_new->payload = p_new;
4183 md_new->thr = map_threads_lookup( tid );
4184
4185 /* and add */
4186 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md_new );
4187
4188 return (void*)p_new;
4189 }
4190 }
4191
hg_cli_malloc_usable_size(ThreadId tid,void * p)4192 static SizeT hg_cli_malloc_usable_size ( ThreadId tid, void* p )
4193 {
4194 MallocMeta *md = VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
4195
4196 // There may be slop, but pretend there isn't because only the asked-for
4197 // area will have been shadowed properly.
4198 return ( md ? md->szB : 0 );
4199 }
4200
4201
4202 /* For error creation: map 'data_addr' to a malloc'd chunk, if any.
4203 Slow linear search. With a bit of hash table help if 'data_addr'
4204 is either the start of a block or up to 15 word-sized steps along
4205 from the start of a block. */
4206
addr_is_in_MM_Chunk(MallocMeta * mm,Addr a)4207 static inline Bool addr_is_in_MM_Chunk( MallocMeta* mm, Addr a )
4208 {
4209 /* Accept 'a' as within 'mm' if 'mm's size is zero and 'a' points
4210 right at it. */
4211 if (UNLIKELY(mm->szB == 0 && a == mm->payload))
4212 return True;
4213 /* else normal interval rules apply */
4214 if (LIKELY(a < mm->payload)) return False;
4215 if (LIKELY(a >= mm->payload + mm->szB)) return False;
4216 return True;
4217 }
4218
HG_(mm_find_containing_block)4219 Bool HG_(mm_find_containing_block)( /*OUT*/ExeContext** where,
4220 /*OUT*/UInt* tnr,
4221 /*OUT*/Addr* payload,
4222 /*OUT*/SizeT* szB,
4223 Addr data_addr )
4224 {
4225 MallocMeta* mm;
4226 Int i;
4227 const Int n_fast_check_words = 16;
4228
4229 /* First, do a few fast searches on the basis that data_addr might
4230 be exactly the start of a block or up to 15 words inside. This
4231 can happen commonly via the creq
4232 _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK. */
4233 for (i = 0; i < n_fast_check_words; i++) {
4234 mm = VG_(HT_lookup)( hg_mallocmeta_table,
4235 data_addr - (UWord)(UInt)i * sizeof(UWord) );
4236 if (UNLIKELY(mm && addr_is_in_MM_Chunk(mm, data_addr)))
4237 goto found;
4238 }
4239
4240 /* Well, this totally sucks. But without using an interval tree or
4241 some such, it's hard to see how to do better. We have to check
4242 every block in the entire table. */
4243 VG_(HT_ResetIter)(hg_mallocmeta_table);
4244 while ( (mm = VG_(HT_Next)(hg_mallocmeta_table)) ) {
4245 if (UNLIKELY(addr_is_in_MM_Chunk(mm, data_addr)))
4246 goto found;
4247 }
4248
4249 /* Not found. Bah. */
4250 return False;
4251 /*NOTREACHED*/
4252
4253 found:
4254 tl_assert(mm);
4255 tl_assert(addr_is_in_MM_Chunk(mm, data_addr));
4256 if (where) *where = mm->where;
4257 if (tnr) *tnr = mm->thr->errmsg_index;
4258 if (payload) *payload = mm->payload;
4259 if (szB) *szB = mm->szB;
4260 return True;
4261 }
4262
4263
4264 /*--------------------------------------------------------------*/
4265 /*--- Instrumentation ---*/
4266 /*--------------------------------------------------------------*/
4267
4268 #define unop(_op, _arg1) IRExpr_Unop((_op),(_arg1))
4269 #define binop(_op, _arg1, _arg2) IRExpr_Binop((_op),(_arg1),(_arg2))
4270 #define mkexpr(_tmp) IRExpr_RdTmp((_tmp))
4271 #define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
4272 #define mkU64(_n) IRExpr_Const(IRConst_U64(_n))
4273 #define assign(_t, _e) IRStmt_WrTmp((_t), (_e))
4274
4275 /* This takes and returns atoms, of course. Not full IRExprs. */
mk_And1(IRSB * sbOut,IRExpr * arg1,IRExpr * arg2)4276 static IRExpr* mk_And1 ( IRSB* sbOut, IRExpr* arg1, IRExpr* arg2 )
4277 {
4278 tl_assert(arg1 && arg2);
4279 tl_assert(isIRAtom(arg1));
4280 tl_assert(isIRAtom(arg2));
4281 /* Generate 32to1(And32(1Uto32(arg1), 1Uto32(arg2))). Appalling
4282 code, I know. */
4283 IRTemp wide1 = newIRTemp(sbOut->tyenv, Ity_I32);
4284 IRTemp wide2 = newIRTemp(sbOut->tyenv, Ity_I32);
4285 IRTemp anded = newIRTemp(sbOut->tyenv, Ity_I32);
4286 IRTemp res = newIRTemp(sbOut->tyenv, Ity_I1);
4287 addStmtToIRSB(sbOut, assign(wide1, unop(Iop_1Uto32, arg1)));
4288 addStmtToIRSB(sbOut, assign(wide2, unop(Iop_1Uto32, arg2)));
4289 addStmtToIRSB(sbOut, assign(anded, binop(Iop_And32, mkexpr(wide1),
4290 mkexpr(wide2))));
4291 addStmtToIRSB(sbOut, assign(res, unop(Iop_32to1, mkexpr(anded))));
4292 return mkexpr(res);
4293 }
4294
instrument_mem_access(IRSB * sbOut,IRExpr * addr,Int szB,Bool isStore,Int hWordTy_szB,Int goff_sp,IRExpr * guard)4295 static void instrument_mem_access ( IRSB* sbOut,
4296 IRExpr* addr,
4297 Int szB,
4298 Bool isStore,
4299 Int hWordTy_szB,
4300 Int goff_sp,
4301 IRExpr* guard ) /* NULL => True */
4302 {
4303 IRType tyAddr = Ity_INVALID;
4304 const HChar* hName = NULL;
4305 void* hAddr = NULL;
4306 Int regparms = 0;
4307 IRExpr** argv = NULL;
4308 IRDirty* di = NULL;
4309
4310 // THRESH is the size of the window above SP (well,
4311 // mostly above) that we assume implies a stack reference.
4312 const Int THRESH = 4096 * 4; // somewhat arbitrary
4313 const Int rz_szB = VG_STACK_REDZONE_SZB;
4314
4315 tl_assert(isIRAtom(addr));
4316 tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8);
4317
4318 tyAddr = typeOfIRExpr( sbOut->tyenv, addr );
4319 tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64);
4320
4321 /* So the effective address is in 'addr' now. */
4322 regparms = 1; // unless stated otherwise
4323 if (isStore) {
4324 switch (szB) {
4325 case 1:
4326 hName = "evh__mem_help_cwrite_1";
4327 hAddr = &evh__mem_help_cwrite_1;
4328 argv = mkIRExprVec_1( addr );
4329 break;
4330 case 2:
4331 hName = "evh__mem_help_cwrite_2";
4332 hAddr = &evh__mem_help_cwrite_2;
4333 argv = mkIRExprVec_1( addr );
4334 break;
4335 case 4:
4336 hName = "evh__mem_help_cwrite_4";
4337 hAddr = &evh__mem_help_cwrite_4;
4338 argv = mkIRExprVec_1( addr );
4339 break;
4340 case 8:
4341 hName = "evh__mem_help_cwrite_8";
4342 hAddr = &evh__mem_help_cwrite_8;
4343 argv = mkIRExprVec_1( addr );
4344 break;
4345 default:
4346 tl_assert(szB > 8 && szB <= 512); /* stay sane */
4347 regparms = 2;
4348 hName = "evh__mem_help_cwrite_N";
4349 hAddr = &evh__mem_help_cwrite_N;
4350 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
4351 break;
4352 }
4353 } else {
4354 switch (szB) {
4355 case 1:
4356 hName = "evh__mem_help_cread_1";
4357 hAddr = &evh__mem_help_cread_1;
4358 argv = mkIRExprVec_1( addr );
4359 break;
4360 case 2:
4361 hName = "evh__mem_help_cread_2";
4362 hAddr = &evh__mem_help_cread_2;
4363 argv = mkIRExprVec_1( addr );
4364 break;
4365 case 4:
4366 hName = "evh__mem_help_cread_4";
4367 hAddr = &evh__mem_help_cread_4;
4368 argv = mkIRExprVec_1( addr );
4369 break;
4370 case 8:
4371 hName = "evh__mem_help_cread_8";
4372 hAddr = &evh__mem_help_cread_8;
4373 argv = mkIRExprVec_1( addr );
4374 break;
4375 default:
4376 tl_assert(szB > 8 && szB <= 512); /* stay sane */
4377 regparms = 2;
4378 hName = "evh__mem_help_cread_N";
4379 hAddr = &evh__mem_help_cread_N;
4380 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
4381 break;
4382 }
4383 }
4384
4385 /* Create the helper. */
4386 tl_assert(hName);
4387 tl_assert(hAddr);
4388 tl_assert(argv);
4389 di = unsafeIRDirty_0_N( regparms,
4390 hName, VG_(fnptr_to_fnentry)( hAddr ),
4391 argv );
4392
4393 if (! HG_(clo_check_stack_refs)) {
4394 /* We're ignoring memory references which are (obviously) to the
4395 stack. In fact just skip stack refs that are within 4 pages
4396 of SP (SP - the redzone, really), as that's simple, easy, and
4397 filters out most stack references. */
4398 /* Generate the guard condition: "(addr - (SP - RZ)) >u N", for
4399 some arbitrary N. If that is true then addr is outside the
4400 range (SP - RZ .. SP + N - RZ). If N is smallish (a few
4401 pages) then we can say addr is within a few pages of SP and
4402 so can't possibly be a heap access, and so can be skipped.
4403
4404 Note that the condition simplifies to
4405 (addr - SP + RZ) >u N
4406 which generates better code in x86/amd64 backends, but it does
4407 not unfortunately simplify to
4408 (addr - SP) >u (N - RZ)
4409 (would be beneficial because N - RZ is a constant) because
4410 wraparound arithmetic messes up the comparison. eg.
4411 20 >u 10 == True,
4412 but (20 - 15) >u (10 - 15) == 5 >u (MAXINT-5) == False.
4413 */
4414 IRTemp sp = newIRTemp(sbOut->tyenv, tyAddr);
4415 addStmtToIRSB( sbOut, assign(sp, IRExpr_Get(goff_sp, tyAddr)));
4416
4417 /* "addr - SP" */
4418 IRTemp addr_minus_sp = newIRTemp(sbOut->tyenv, tyAddr);
4419 addStmtToIRSB(
4420 sbOut,
4421 assign(addr_minus_sp,
4422 tyAddr == Ity_I32
4423 ? binop(Iop_Sub32, addr, mkexpr(sp))
4424 : binop(Iop_Sub64, addr, mkexpr(sp)))
4425 );
4426
4427 /* "addr - SP + RZ" */
4428 IRTemp diff = newIRTemp(sbOut->tyenv, tyAddr);
4429 addStmtToIRSB(
4430 sbOut,
4431 assign(diff,
4432 tyAddr == Ity_I32
4433 ? binop(Iop_Add32, mkexpr(addr_minus_sp), mkU32(rz_szB))
4434 : binop(Iop_Add64, mkexpr(addr_minus_sp), mkU64(rz_szB)))
4435 );
4436
4437 /* guardA == "guard on the address" */
4438 IRTemp guardA = newIRTemp(sbOut->tyenv, Ity_I1);
4439 addStmtToIRSB(
4440 sbOut,
4441 assign(guardA,
4442 tyAddr == Ity_I32
4443 ? binop(Iop_CmpLT32U, mkU32(THRESH), mkexpr(diff))
4444 : binop(Iop_CmpLT64U, mkU64(THRESH), mkexpr(diff)))
4445 );
4446 di->guard = mkexpr(guardA);
4447 }
4448
4449 /* If there's a guard on the access itself (as supplied by the
4450 caller of this routine), we need to AND that in to any guard we
4451 might already have. */
4452 if (guard) {
4453 di->guard = mk_And1(sbOut, di->guard, guard);
4454 }
4455
4456 /* Add the helper. */
4457 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
4458 }
4459
4460
4461 /* Figure out if GA is a guest code address in the dynamic linker, and
4462 if so return True. Otherwise (and in case of any doubt) return
4463 False. (sidedly safe w/ False as the safe value) */
is_in_dynamic_linker_shared_object(Addr ga)4464 static Bool is_in_dynamic_linker_shared_object( Addr ga )
4465 {
4466 DebugInfo* dinfo;
4467 const HChar* soname;
4468 if (0) return False;
4469
4470 dinfo = VG_(find_DebugInfo)( ga );
4471 if (!dinfo) return False;
4472
4473 soname = VG_(DebugInfo_get_soname)(dinfo);
4474 tl_assert(soname);
4475 if (0) VG_(printf)("%s\n", soname);
4476
4477 # if defined(VGO_linux)
4478 if (VG_STREQ(soname, VG_U_LD_LINUX_SO_3)) return True;
4479 if (VG_STREQ(soname, VG_U_LD_LINUX_SO_2)) return True;
4480 if (VG_STREQ(soname, VG_U_LD_LINUX_X86_64_SO_2)) return True;
4481 if (VG_STREQ(soname, VG_U_LD64_SO_1)) return True;
4482 if (VG_STREQ(soname, VG_U_LD64_SO_2)) return True;
4483 if (VG_STREQ(soname, VG_U_LD_SO_1)) return True;
4484 if (VG_STREQ(soname, VG_U_LD_LINUX_AARCH64_SO_1)) return True;
4485 if (VG_STREQ(soname, VG_U_LD_LINUX_ARMHF_SO_3)) return True;
4486 # elif defined(VGO_darwin)
4487 if (VG_STREQ(soname, VG_U_DYLD)) return True;
4488 # else
4489 # error "Unsupported OS"
4490 # endif
4491 return False;
4492 }
4493
4494 static
hg_instrument(VgCallbackClosure * closure,IRSB * bbIn,const VexGuestLayout * layout,const VexGuestExtents * vge,const VexArchInfo * archinfo_host,IRType gWordTy,IRType hWordTy)4495 IRSB* hg_instrument ( VgCallbackClosure* closure,
4496 IRSB* bbIn,
4497 const VexGuestLayout* layout,
4498 const VexGuestExtents* vge,
4499 const VexArchInfo* archinfo_host,
4500 IRType gWordTy, IRType hWordTy )
4501 {
4502 Int i;
4503 IRSB* bbOut;
4504 Addr cia; /* address of current insn */
4505 IRStmt* st;
4506 Bool inLDSO = False;
4507 Addr inLDSOmask4K = 1; /* mismatches on first check */
4508
4509 const Int goff_sp = layout->offset_SP;
4510
4511 if (gWordTy != hWordTy) {
4512 /* We don't currently support this case. */
4513 VG_(tool_panic)("host/guest word size mismatch");
4514 }
4515
4516 if (VKI_PAGE_SIZE < 4096 || VG_(log2)(VKI_PAGE_SIZE) == -1) {
4517 VG_(tool_panic)("implausible or too-small VKI_PAGE_SIZE");
4518 }
4519
4520 /* Set up BB */
4521 bbOut = emptyIRSB();
4522 bbOut->tyenv = deepCopyIRTypeEnv(bbIn->tyenv);
4523 bbOut->next = deepCopyIRExpr(bbIn->next);
4524 bbOut->jumpkind = bbIn->jumpkind;
4525 bbOut->offsIP = bbIn->offsIP;
4526
4527 // Copy verbatim any IR preamble preceding the first IMark
4528 i = 0;
4529 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
4530 addStmtToIRSB( bbOut, bbIn->stmts[i] );
4531 i++;
4532 }
4533
4534 // Get the first statement, and initial cia from it
4535 tl_assert(bbIn->stmts_used > 0);
4536 tl_assert(i < bbIn->stmts_used);
4537 st = bbIn->stmts[i];
4538 tl_assert(Ist_IMark == st->tag);
4539 cia = st->Ist.IMark.addr;
4540 st = NULL;
4541
4542 for (/*use current i*/; i < bbIn->stmts_used; i++) {
4543 st = bbIn->stmts[i];
4544 tl_assert(st);
4545 tl_assert(isFlatIRStmt(st));
4546 switch (st->tag) {
4547 case Ist_NoOp:
4548 case Ist_AbiHint:
4549 case Ist_Put:
4550 case Ist_PutI:
4551 case Ist_Exit:
4552 /* None of these can contain any memory references. */
4553 break;
4554
4555 case Ist_IMark:
4556 /* no mem refs, but note the insn address. */
4557 cia = st->Ist.IMark.addr;
4558 /* Don't instrument the dynamic linker. It generates a
4559 lot of races which we just expensively suppress, so
4560 it's pointless.
4561
4562 Avoid flooding is_in_dynamic_linker_shared_object with
4563 requests by only checking at transitions between 4K
4564 pages. */
4565 if ((cia & ~(Addr)0xFFF) != inLDSOmask4K) {
4566 if (0) VG_(printf)("NEW %#lx\n", cia);
4567 inLDSOmask4K = cia & ~(Addr)0xFFF;
4568 inLDSO = is_in_dynamic_linker_shared_object(cia);
4569 } else {
4570 if (0) VG_(printf)("old %#lx\n", cia);
4571 }
4572 break;
4573
4574 case Ist_MBE:
4575 switch (st->Ist.MBE.event) {
4576 case Imbe_Fence:
4577 case Imbe_CancelReservation:
4578 break; /* not interesting */
4579 default:
4580 goto unhandled;
4581 }
4582 break;
4583
4584 case Ist_CAS: {
4585 /* Atomic read-modify-write cycle. Just pretend it's a
4586 read. */
4587 IRCAS* cas = st->Ist.CAS.details;
4588 Bool isDCAS = cas->oldHi != IRTemp_INVALID;
4589 if (isDCAS) {
4590 tl_assert(cas->expdHi);
4591 tl_assert(cas->dataHi);
4592 } else {
4593 tl_assert(!cas->expdHi);
4594 tl_assert(!cas->dataHi);
4595 }
4596 /* Just be boring about it. */
4597 if (!inLDSO) {
4598 instrument_mem_access(
4599 bbOut,
4600 cas->addr,
4601 (isDCAS ? 2 : 1)
4602 * sizeofIRType(typeOfIRExpr(bbIn->tyenv, cas->dataLo)),
4603 False/*!isStore*/,
4604 sizeofIRType(hWordTy), goff_sp,
4605 NULL/*no-guard*/
4606 );
4607 }
4608 break;
4609 }
4610
4611 case Ist_LLSC: {
4612 /* We pretend store-conditionals don't exist, viz, ignore
4613 them. Whereas load-linked's are treated the same as
4614 normal loads. */
4615 IRType dataTy;
4616 if (st->Ist.LLSC.storedata == NULL) {
4617 /* LL */
4618 dataTy = typeOfIRTemp(bbIn->tyenv, st->Ist.LLSC.result);
4619 if (!inLDSO) {
4620 instrument_mem_access(
4621 bbOut,
4622 st->Ist.LLSC.addr,
4623 sizeofIRType(dataTy),
4624 False/*!isStore*/,
4625 sizeofIRType(hWordTy), goff_sp,
4626 NULL/*no-guard*/
4627 );
4628 }
4629 } else {
4630 /* SC */
4631 /*ignore */
4632 }
4633 break;
4634 }
4635
4636 case Ist_Store:
4637 if (!inLDSO) {
4638 instrument_mem_access(
4639 bbOut,
4640 st->Ist.Store.addr,
4641 sizeofIRType(typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data)),
4642 True/*isStore*/,
4643 sizeofIRType(hWordTy), goff_sp,
4644 NULL/*no-guard*/
4645 );
4646 }
4647 break;
4648
4649 case Ist_StoreG: {
4650 IRStoreG* sg = st->Ist.StoreG.details;
4651 IRExpr* data = sg->data;
4652 IRExpr* addr = sg->addr;
4653 IRType type = typeOfIRExpr(bbIn->tyenv, data);
4654 tl_assert(type != Ity_INVALID);
4655 instrument_mem_access( bbOut, addr, sizeofIRType(type),
4656 True/*isStore*/,
4657 sizeofIRType(hWordTy),
4658 goff_sp, sg->guard );
4659 break;
4660 }
4661
4662 case Ist_LoadG: {
4663 IRLoadG* lg = st->Ist.LoadG.details;
4664 IRType type = Ity_INVALID; /* loaded type */
4665 IRType typeWide = Ity_INVALID; /* after implicit widening */
4666 IRExpr* addr = lg->addr;
4667 typeOfIRLoadGOp(lg->cvt, &typeWide, &type);
4668 tl_assert(type != Ity_INVALID);
4669 instrument_mem_access( bbOut, addr, sizeofIRType(type),
4670 False/*!isStore*/,
4671 sizeofIRType(hWordTy),
4672 goff_sp, lg->guard );
4673 break;
4674 }
4675
4676 case Ist_WrTmp: {
4677 IRExpr* data = st->Ist.WrTmp.data;
4678 if (data->tag == Iex_Load) {
4679 if (!inLDSO) {
4680 instrument_mem_access(
4681 bbOut,
4682 data->Iex.Load.addr,
4683 sizeofIRType(data->Iex.Load.ty),
4684 False/*!isStore*/,
4685 sizeofIRType(hWordTy), goff_sp,
4686 NULL/*no-guard*/
4687 );
4688 }
4689 }
4690 break;
4691 }
4692
4693 case Ist_Dirty: {
4694 Int dataSize;
4695 IRDirty* d = st->Ist.Dirty.details;
4696 if (d->mFx != Ifx_None) {
4697 /* This dirty helper accesses memory. Collect the
4698 details. */
4699 tl_assert(d->mAddr != NULL);
4700 tl_assert(d->mSize != 0);
4701 dataSize = d->mSize;
4702 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) {
4703 if (!inLDSO) {
4704 instrument_mem_access(
4705 bbOut, d->mAddr, dataSize, False/*!isStore*/,
4706 sizeofIRType(hWordTy), goff_sp, NULL/*no-guard*/
4707 );
4708 }
4709 }
4710 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) {
4711 if (!inLDSO) {
4712 instrument_mem_access(
4713 bbOut, d->mAddr, dataSize, True/*isStore*/,
4714 sizeofIRType(hWordTy), goff_sp, NULL/*no-guard*/
4715 );
4716 }
4717 }
4718 } else {
4719 tl_assert(d->mAddr == NULL);
4720 tl_assert(d->mSize == 0);
4721 }
4722 break;
4723 }
4724
4725 default:
4726 unhandled:
4727 ppIRStmt(st);
4728 tl_assert(0);
4729
4730 } /* switch (st->tag) */
4731
4732 addStmtToIRSB( bbOut, st );
4733 } /* iterate over bbIn->stmts */
4734
4735 return bbOut;
4736 }
4737
4738 #undef binop
4739 #undef mkexpr
4740 #undef mkU32
4741 #undef mkU64
4742 #undef assign
4743
4744
4745 /*----------------------------------------------------------------*/
4746 /*--- Client requests ---*/
4747 /*----------------------------------------------------------------*/
4748
4749 /* Sheesh. Yet another goddam finite map. */
4750 static WordFM* map_pthread_t_to_Thread = NULL; /* pthread_t -> Thread* */
4751
map_pthread_t_to_Thread_INIT(void)4752 static void map_pthread_t_to_Thread_INIT ( void ) {
4753 if (UNLIKELY(map_pthread_t_to_Thread == NULL)) {
4754 map_pthread_t_to_Thread = VG_(newFM)( HG_(zalloc), "hg.mpttT.1",
4755 HG_(free), NULL );
4756 }
4757 }
4758
4759 /* A list of Ada dependent tasks and their masters. Used for implementing
4760 the Ada task termination semantic as implemented by the
4761 gcc gnat Ada runtime. */
4762 typedef
4763 struct {
4764 void* dependent; // Ada Task Control Block of the Dependent
4765 void* master; // ATCB of the master
4766 Word master_level; // level of dependency between master and dependent
4767 Thread* hg_dependent; // helgrind Thread* for dependent task.
4768 }
4769 GNAT_dmml;
4770 static XArray* gnat_dmmls; /* of GNAT_dmml */
gnat_dmmls_INIT(void)4771 static void gnat_dmmls_INIT (void)
4772 {
4773 if (UNLIKELY(gnat_dmmls == NULL)) {
4774 gnat_dmmls = VG_(newXA) (HG_(zalloc), "hg.gnat_md.1",
4775 HG_(free),
4776 sizeof(GNAT_dmml) );
4777 }
4778 }
print_monitor_help(void)4779 static void print_monitor_help ( void )
4780 {
4781 VG_(gdb_printf)
4782 (
4783 "\n"
4784 "helgrind monitor commands:\n"
4785 " info locks [lock_addr] : show status of lock at addr lock_addr\n"
4786 " with no lock_addr, show status of all locks\n"
4787 " accesshistory <addr> [<len>] : show access history recorded\n"
4788 " for <len> (or 1) bytes at <addr>\n"
4789 "\n");
4790 }
4791
4792 /* return True if request recognised, False otherwise */
handle_gdb_monitor_command(ThreadId tid,HChar * req)4793 static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
4794 {
4795 HChar* wcmd;
4796 HChar s[VG_(strlen(req))]; /* copy for strtok_r */
4797 HChar *ssaveptr;
4798 Int kwdid;
4799
4800 VG_(strcpy) (s, req);
4801
4802 wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
4803 /* NB: if possible, avoid introducing a new command below which
4804 starts with the same first letter(s) as an already existing
4805 command. This ensures a shorter abbreviation for the user. */
4806 switch (VG_(keyword_id)
4807 ("help info accesshistory",
4808 wcmd, kwd_report_duplicated_matches)) {
4809 case -2: /* multiple matches */
4810 return True;
4811 case -1: /* not found */
4812 return False;
4813 case 0: /* help */
4814 print_monitor_help();
4815 return True;
4816 case 1: /* info */
4817 wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
4818 switch (kwdid = VG_(keyword_id)
4819 ("locks",
4820 wcmd, kwd_report_all)) {
4821 case -2:
4822 case -1:
4823 break;
4824 case 0: // locks
4825 {
4826 const HChar* wa;
4827 Addr lk_addr = 0;
4828 Bool lk_shown = False;
4829 Bool all_locks = True;
4830 Int i;
4831 Lock* lk;
4832
4833 wa = VG_(strtok_r) (NULL, " ", &ssaveptr);
4834 if (wa != NULL) {
4835 if (VG_(parse_Addr) (&wa, &lk_addr) )
4836 all_locks = False;
4837 else {
4838 VG_(gdb_printf) ("missing or malformed address\n");
4839 }
4840 }
4841 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next) {
4842 if (all_locks || lk_addr == lk->guestaddr) {
4843 pp_Lock(0, lk,
4844 True /* show_lock_addrdescr */,
4845 False /* show_internal_data */);
4846 lk_shown = True;
4847 }
4848 }
4849 if (i == 0)
4850 VG_(gdb_printf) ("no locks\n");
4851 if (!all_locks && !lk_shown)
4852 VG_(gdb_printf) ("lock with address %p not found\n",
4853 (void*)lk_addr);
4854 }
4855 break;
4856 default:
4857 tl_assert(0);
4858 }
4859 return True;
4860
4861 case 2: /* accesshistory */
4862 {
4863 Addr address;
4864 SizeT szB = 1;
4865 if (VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr)) {
4866 if (szB >= 1)
4867 libhb_event_map_access_history (address, szB, HG_(print_access));
4868 else
4869 VG_(gdb_printf) ("len must be >=1\n");
4870 }
4871 return True;
4872 }
4873
4874 default:
4875 tl_assert(0);
4876 return False;
4877 }
4878 }
4879
4880 static
hg_handle_client_request(ThreadId tid,UWord * args,UWord * ret)4881 Bool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret)
4882 {
4883 if (!VG_IS_TOOL_USERREQ('H','G',args[0])
4884 && VG_USERREQ__GDB_MONITOR_COMMAND != args[0])
4885 return False;
4886
4887 /* Anything that gets past the above check is one of ours, so we
4888 should be able to handle it. */
4889
4890 /* default, meaningless return value, unless otherwise set */
4891 *ret = 0;
4892
4893 switch (args[0]) {
4894
4895 /* --- --- User-visible client requests --- --- */
4896
4897 case VG_USERREQ__HG_CLEAN_MEMORY:
4898 if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY(%#lx,%ld)\n",
4899 args[1], args[2]);
4900 /* Call die_mem to (expensively) tidy up properly, if there
4901 are any held locks etc in the area. Calling evh__die_mem
4902 and then evh__new_mem is a bit inefficient; probably just
4903 the latter would do. */
4904 if (args[2] > 0) { /* length */
4905 evh__die_mem(args[1], args[2]);
4906 /* and then set it to New */
4907 evh__new_mem(args[1], args[2]);
4908 }
4909 break;
4910
4911 case _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK: {
4912 Addr payload = 0;
4913 SizeT pszB = 0;
4914 if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK(%#lx)\n",
4915 args[1]);
4916 if (HG_(mm_find_containing_block)(NULL, NULL,
4917 &payload, &pszB, args[1])) {
4918 if (pszB > 0) {
4919 evh__die_mem(payload, pszB);
4920 evh__new_mem(payload, pszB);
4921 }
4922 *ret = pszB;
4923 } else {
4924 *ret = (UWord)-1;
4925 }
4926 break;
4927 }
4928
4929 case _VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED:
4930 if (0) VG_(printf)("HG_ARANGE_MAKE_UNTRACKED(%#lx,%ld)\n",
4931 args[1], args[2]);
4932 if (args[2] > 0) { /* length */
4933 evh__untrack_mem(args[1], args[2]);
4934 }
4935 break;
4936
4937 case _VG_USERREQ__HG_ARANGE_MAKE_TRACKED:
4938 if (0) VG_(printf)("HG_ARANGE_MAKE_TRACKED(%#lx,%ld)\n",
4939 args[1], args[2]);
4940 if (args[2] > 0) { /* length */
4941 evh__new_mem(args[1], args[2]);
4942 }
4943 break;
4944
4945 case _VG_USERREQ__HG_GET_ABITS:
4946 if (0) VG_(printf)("HG_GET_ABITS(%#lx,%#lx,%ld)\n",
4947 args[1], args[2], args[3]);
4948 UChar *zzabit = (UChar *) args[2];
4949 if (zzabit == NULL
4950 || VG_(am_is_valid_for_client)((Addr)zzabit, (SizeT)args[3],
4951 VKI_PROT_READ|VKI_PROT_WRITE))
4952 *ret = (UWord) libhb_srange_get_abits ((Addr) args[1],
4953 (UChar*) args[2],
4954 (SizeT) args[3]);
4955 else
4956 *ret = -1;
4957 break;
4958
4959 /* --- --- Client requests for Helgrind's use only --- --- */
4960
4961 /* Some thread is telling us its pthread_t value. Record the
4962 binding between that and the associated Thread*, so we can
4963 later find the Thread* again when notified of a join by the
4964 thread. */
4965 case _VG_USERREQ__HG_SET_MY_PTHREAD_T: {
4966 Thread* my_thr = NULL;
4967 if (0)
4968 VG_(printf)("SET_MY_PTHREAD_T (tid %d): pthread_t = %p\n", (Int)tid,
4969 (void*)args[1]);
4970 map_pthread_t_to_Thread_INIT();
4971 my_thr = map_threads_maybe_lookup( tid );
4972 /* This assertion should hold because the map_threads (tid to
4973 Thread*) binding should have been made at the point of
4974 low-level creation of this thread, which should have
4975 happened prior to us getting this client request for it.
4976 That's because this client request is sent from
4977 client-world from the 'thread_wrapper' function, which
4978 only runs once the thread has been low-level created. */
4979 tl_assert(my_thr != NULL);
4980 /* So now we know that (pthread_t)args[1] is associated with
4981 (Thread*)my_thr. Note that down. */
4982 if (0)
4983 VG_(printf)("XXXX: bind pthread_t %p to Thread* %p\n",
4984 (void*)args[1], (void*)my_thr );
4985 VG_(addToFM)( map_pthread_t_to_Thread, (UWord)args[1], (UWord)my_thr );
4986 break;
4987 }
4988
4989 case _VG_USERREQ__HG_PTH_API_ERROR: {
4990 Thread* my_thr = NULL;
4991 map_pthread_t_to_Thread_INIT();
4992 my_thr = map_threads_maybe_lookup( tid );
4993 tl_assert(my_thr); /* See justification above in SET_MY_PTHREAD_T */
4994 HG_(record_error_PthAPIerror)(
4995 my_thr, (HChar*)args[1], (UWord)args[2], (HChar*)args[3] );
4996 break;
4997 }
4998
4999 /* This thread (tid) has completed a join with the quitting
5000 thread whose pthread_t is in args[1]. */
5001 case _VG_USERREQ__HG_PTHREAD_JOIN_POST: {
5002 Thread* thr_q = NULL; /* quitter Thread* */
5003 Bool found = False;
5004 if (0)
5005 VG_(printf)("NOTIFY_JOIN_COMPLETE (tid %d): quitter = %p\n", (Int)tid,
5006 (void*)args[1]);
5007 map_pthread_t_to_Thread_INIT();
5008 found = VG_(lookupFM)( map_pthread_t_to_Thread,
5009 NULL, (UWord*)&thr_q, (UWord)args[1] );
5010 /* Can this fail? It would mean that our pthread_join
5011 wrapper observed a successful join on args[1] yet that
5012 thread never existed (or at least, it never lodged an
5013 entry in the mapping (via SET_MY_PTHREAD_T)). Which
5014 sounds like a bug in the threads library. */
5015 // FIXME: get rid of this assertion; handle properly
5016 tl_assert(found);
5017 if (found) {
5018 if (0)
5019 VG_(printf)(".................... quitter Thread* = %p\n",
5020 thr_q);
5021 evh__HG_PTHREAD_JOIN_POST( tid, thr_q );
5022 }
5023 break;
5024 }
5025
5026 /* This thread (tid) is informing us of its master. */
5027 case _VG_USERREQ__HG_GNAT_MASTER_HOOK: {
5028 GNAT_dmml dmml;
5029 dmml.dependent = (void*)args[1];
5030 dmml.master = (void*)args[2];
5031 dmml.master_level = (Word)args[3];
5032 dmml.hg_dependent = map_threads_maybe_lookup( tid );
5033 tl_assert(dmml.hg_dependent);
5034
5035 if (0)
5036 VG_(printf)("HG_GNAT_MASTER_HOOK (tid %d): "
5037 "dependent = %p master = %p master_level = %ld"
5038 " dependent Thread* = %p\n",
5039 (Int)tid, dmml.dependent, dmml.master, dmml.master_level,
5040 dmml.hg_dependent);
5041 gnat_dmmls_INIT();
5042 VG_(addToXA) (gnat_dmmls, &dmml);
5043 break;
5044 }
5045
5046 /* This thread (tid) is informing us that it has completed a
5047 master. */
5048 case _VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK: {
5049 Word n;
5050 const Thread *stayer = map_threads_maybe_lookup( tid );
5051 const void *master = (void*)args[1];
5052 const Word master_level = (Word) args[2];
5053 tl_assert(stayer);
5054
5055 if (0)
5056 VG_(printf)("HG_GNAT_MASTER_COMPLETED_HOOK (tid %d): "
5057 "self_id = %p master_level = %ld Thread* = %p\n",
5058 (Int)tid, master, master_level, stayer);
5059
5060 gnat_dmmls_INIT();
5061 /* Reverse loop on the array, simulating a pthread_join for
5062 the Dependent tasks of the completed master, and removing
5063 them from the array. */
5064 for (n = VG_(sizeXA) (gnat_dmmls) - 1; n >= 0; n--) {
5065 GNAT_dmml *dmml = (GNAT_dmml*) VG_(indexXA)(gnat_dmmls, n);
5066 if (dmml->master == master
5067 && dmml->master_level == master_level) {
5068 if (0)
5069 VG_(printf)("quitter %p dependency to stayer %p\n",
5070 dmml->hg_dependent->hbthr, stayer->hbthr);
5071 tl_assert(dmml->hg_dependent->hbthr != stayer->hbthr);
5072 generate_quitter_stayer_dependence (dmml->hg_dependent->hbthr,
5073 stayer->hbthr);
5074 VG_(removeIndexXA) (gnat_dmmls, n);
5075 }
5076 }
5077 break;
5078 }
5079
5080 /* EXPOSITION only: by intercepting lock init events we can show
5081 the user where the lock was initialised, rather than only
5082 being able to show where it was first locked. Intercepting
5083 lock initialisations is not necessary for the basic operation
5084 of the race checker. */
5085 case _VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST:
5086 evh__HG_PTHREAD_MUTEX_INIT_POST( tid, (void*)args[1], args[2] );
5087 break;
5088
5089 /* mutex=arg[1], mutex_is_init=arg[2] */
5090 case _VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE:
5091 evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, (void*)args[1], args[2] != 0 );
5092 break;
5093
5094 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE: // pth_mx_t*
5095 evh__HG_PTHREAD_MUTEX_UNLOCK_PRE( tid, (void*)args[1] );
5096 break;
5097
5098 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST: // pth_mx_t*
5099 evh__HG_PTHREAD_MUTEX_UNLOCK_POST( tid, (void*)args[1] );
5100 break;
5101
5102 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE: // pth_mx_t*, Word
5103 evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
5104 break;
5105
5106 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST: // pth_mx_t*
5107 evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
5108 break;
5109
5110 /* This thread is about to do pthread_cond_signal on the
5111 pthread_cond_t* in arg[1]. Ditto pthread_cond_broadcast. */
5112 case _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE:
5113 case _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE:
5114 evh__HG_PTHREAD_COND_SIGNAL_PRE( tid, (void*)args[1] );
5115 break;
5116
5117 /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2].
5118 Returns a flag indicating whether or not the mutex is believed to be
5119 valid for this operation. */
5120 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE: {
5121 Bool mutex_is_valid
5122 = evh__HG_PTHREAD_COND_WAIT_PRE( tid, (void*)args[1],
5123 (void*)args[2] );
5124 *ret = mutex_is_valid ? 1 : 0;
5125 break;
5126 }
5127
5128 /* Thread successfully completed pthread_cond_init:
5129 cond=arg[1], cond_attr=arg[2] */
5130 case _VG_USERREQ__HG_PTHREAD_COND_INIT_POST:
5131 evh__HG_PTHREAD_COND_INIT_POST( tid,
5132 (void*)args[1], (void*)args[2] );
5133 break;
5134
5135 /* cond=arg[1], cond_is_init=arg[2] */
5136 case _VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE:
5137 evh__HG_PTHREAD_COND_DESTROY_PRE( tid, (void*)args[1], args[2] != 0 );
5138 break;
5139
5140 /* Thread successfully completed pthread_cond_wait, cond=arg[1],
5141 mutex=arg[2] */
5142 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_POST:
5143 evh__HG_PTHREAD_COND_WAIT_POST( tid,
5144 (void*)args[1], (void*)args[2],
5145 (Bool)args[3] );
5146 break;
5147
5148 case _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST:
5149 evh__HG_PTHREAD_RWLOCK_INIT_POST( tid, (void*)args[1] );
5150 break;
5151
5152 case _VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE:
5153 evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( tid, (void*)args[1] );
5154 break;
5155
5156 /* rwlock=arg[1], isW=arg[2], isTryLock=arg[3] */
5157 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE:
5158 evh__HG_PTHREAD_RWLOCK_LOCK_PRE( tid, (void*)args[1],
5159 args[2], args[3] );
5160 break;
5161
5162 /* rwlock=arg[1], isW=arg[2] */
5163 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST:
5164 evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
5165 break;
5166
5167 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE:
5168 evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
5169 break;
5170
5171 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST:
5172 evh__HG_PTHREAD_RWLOCK_UNLOCK_POST( tid, (void*)args[1] );
5173 break;
5174
5175 case _VG_USERREQ__HG_POSIX_SEM_INIT_POST: /* sem_t*, unsigned long */
5176 evh__HG_POSIX_SEM_INIT_POST( tid, (void*)args[1], args[2] );
5177 break;
5178
5179 case _VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE: /* sem_t* */
5180 evh__HG_POSIX_SEM_DESTROY_PRE( tid, (void*)args[1] );
5181 break;
5182
5183 case _VG_USERREQ__HG_POSIX_SEM_POST_PRE: /* sem_t* */
5184 evh__HG_POSIX_SEM_POST_PRE( tid, (void*)args[1] );
5185 break;
5186
5187 case _VG_USERREQ__HG_POSIX_SEM_WAIT_POST: /* sem_t* */
5188 evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] );
5189 break;
5190
5191 case _VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE:
5192 /* pth_bar_t*, ulong count, ulong resizable */
5193 evh__HG_PTHREAD_BARRIER_INIT_PRE( tid, (void*)args[1],
5194 args[2], args[3] );
5195 break;
5196
5197 case _VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE:
5198 /* pth_bar_t*, ulong newcount */
5199 evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( tid, (void*)args[1],
5200 args[2] );
5201 break;
5202
5203 case _VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE:
5204 /* pth_bar_t* */
5205 evh__HG_PTHREAD_BARRIER_WAIT_PRE( tid, (void*)args[1] );
5206 break;
5207
5208 case _VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE:
5209 /* pth_bar_t* */
5210 evh__HG_PTHREAD_BARRIER_DESTROY_PRE( tid, (void*)args[1] );
5211 break;
5212
5213 case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE:
5214 /* pth_spinlock_t* */
5215 evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( tid, (void*)args[1] );
5216 break;
5217
5218 case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST:
5219 /* pth_spinlock_t* */
5220 evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( tid, (void*)args[1] );
5221 break;
5222
5223 case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE:
5224 /* pth_spinlock_t*, Word */
5225 evh__HG_PTHREAD_SPIN_LOCK_PRE( tid, (void*)args[1], args[2] );
5226 break;
5227
5228 case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST:
5229 /* pth_spinlock_t* */
5230 evh__HG_PTHREAD_SPIN_LOCK_POST( tid, (void*)args[1] );
5231 break;
5232
5233 case _VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE:
5234 /* pth_spinlock_t* */
5235 evh__HG_PTHREAD_SPIN_DESTROY_PRE( tid, (void*)args[1] );
5236 break;
5237
5238 case _VG_USERREQ__HG_CLIENTREQ_UNIMP: {
5239 /* HChar* who */
5240 HChar* who = (HChar*)args[1];
5241 HChar buf[50 + 50];
5242 Thread* thr = map_threads_maybe_lookup( tid );
5243 tl_assert( thr ); /* I must be mapped */
5244 tl_assert( who );
5245 tl_assert( VG_(strlen)(who) <= 50 );
5246 VG_(sprintf)(buf, "Unimplemented client request macro \"%s\"", who );
5247 /* record_error_Misc strdup's buf, so this is safe: */
5248 HG_(record_error_Misc)( thr, buf );
5249 break;
5250 }
5251
5252 case _VG_USERREQ__HG_USERSO_SEND_PRE:
5253 /* UWord arbitrary-SO-tag */
5254 evh__HG_USERSO_SEND_PRE( tid, args[1] );
5255 break;
5256
5257 case _VG_USERREQ__HG_USERSO_RECV_POST:
5258 /* UWord arbitrary-SO-tag */
5259 evh__HG_USERSO_RECV_POST( tid, args[1] );
5260 break;
5261
5262 case _VG_USERREQ__HG_USERSO_FORGET_ALL:
5263 /* UWord arbitrary-SO-tag */
5264 evh__HG_USERSO_FORGET_ALL( tid, args[1] );
5265 break;
5266
5267 case VG_USERREQ__GDB_MONITOR_COMMAND: {
5268 Bool handled = handle_gdb_monitor_command (tid, (HChar*)args[1]);
5269 if (handled)
5270 *ret = 1;
5271 else
5272 *ret = 0;
5273 return handled;
5274 }
5275
5276 default:
5277 /* Unhandled Helgrind client request! */
5278 tl_assert2(0, "unhandled Helgrind client request 0x%lx",
5279 args[0]);
5280 }
5281
5282 return True;
5283 }
5284
5285
5286 /*----------------------------------------------------------------*/
5287 /*--- Setup ---*/
5288 /*----------------------------------------------------------------*/
5289
hg_process_cmd_line_option(const HChar * arg)5290 static Bool hg_process_cmd_line_option ( const HChar* arg )
5291 {
5292 const HChar* tmp_str;
5293
5294 if VG_BOOL_CLO(arg, "--track-lockorders",
5295 HG_(clo_track_lockorders)) {}
5296 else if VG_BOOL_CLO(arg, "--cmp-race-err-addrs",
5297 HG_(clo_cmp_race_err_addrs)) {}
5298
5299 else if VG_XACT_CLO(arg, "--history-level=none",
5300 HG_(clo_history_level), 0);
5301 else if VG_XACT_CLO(arg, "--history-level=approx",
5302 HG_(clo_history_level), 1);
5303 else if VG_XACT_CLO(arg, "--history-level=full",
5304 HG_(clo_history_level), 2);
5305
5306 else if VG_BINT_CLO(arg, "--conflict-cache-size",
5307 HG_(clo_conflict_cache_size), 10*1000, 150*1000*1000) {}
5308
5309 /* "stuvwx" --> stuvwx (binary) */
5310 else if VG_STR_CLO(arg, "--hg-sanity-flags", tmp_str) {
5311 Int j;
5312
5313 if (6 != VG_(strlen)(tmp_str)) {
5314 VG_(message)(Vg_UserMsg,
5315 "--hg-sanity-flags argument must have 6 digits\n");
5316 return False;
5317 }
5318 for (j = 0; j < 6; j++) {
5319 if ('0' == tmp_str[j]) { /* do nothing */ }
5320 else if ('1' == tmp_str[j]) HG_(clo_sanity_flags) |= (1 << (6-1-j));
5321 else {
5322 VG_(message)(Vg_UserMsg, "--hg-sanity-flags argument can "
5323 "only contain 0s and 1s\n");
5324 return False;
5325 }
5326 }
5327 if (0) VG_(printf)("XXX sanity flags: 0x%lx\n", HG_(clo_sanity_flags));
5328 }
5329
5330 else if VG_BOOL_CLO(arg, "--free-is-write",
5331 HG_(clo_free_is_write)) {}
5332
5333 else if VG_XACT_CLO(arg, "--vts-pruning=never",
5334 HG_(clo_vts_pruning), 0);
5335 else if VG_XACT_CLO(arg, "--vts-pruning=auto",
5336 HG_(clo_vts_pruning), 1);
5337 else if VG_XACT_CLO(arg, "--vts-pruning=always",
5338 HG_(clo_vts_pruning), 2);
5339
5340 else if VG_BOOL_CLO(arg, "--check-stack-refs",
5341 HG_(clo_check_stack_refs)) {}
5342
5343 else
5344 return VG_(replacement_malloc_process_cmd_line_option)(arg);
5345
5346 return True;
5347 }
5348
hg_print_usage(void)5349 static void hg_print_usage ( void )
5350 {
5351 VG_(printf)(
5352 " --free-is-write=no|yes treat heap frees as writes [no]\n"
5353 " --track-lockorders=no|yes show lock ordering errors? [yes]\n"
5354 " --history-level=none|approx|full [full]\n"
5355 " full: show both stack traces for a data race (can be very slow)\n"
5356 " approx: full trace for one thread, approx for the other (faster)\n"
5357 " none: only show trace for one thread in a race (fastest)\n"
5358 " --conflict-cache-size=N size of 'full' history cache [2000000]\n"
5359 " --check-stack-refs=no|yes race-check reads and writes on the\n"
5360 " main stack and thread stacks? [yes]\n"
5361 );
5362 }
5363
hg_print_debug_usage(void)5364 static void hg_print_debug_usage ( void )
5365 {
5366 VG_(printf)(" --cmp-race-err-addrs=no|yes are data addresses in "
5367 "race errors significant? [no]\n");
5368 VG_(printf)(" --hg-sanity-flags=<XXXXXX> sanity check "
5369 " at events (X = 0|1) [000000]\n");
5370 VG_(printf)(" --hg-sanity-flags values:\n");
5371 VG_(printf)(" 010000 after changes to "
5372 "lock-order-acquisition-graph\n");
5373 VG_(printf)(" 001000 at memory accesses (NB: not currently used)\n");
5374 VG_(printf)(" 000100 at mem permission setting for "
5375 "ranges >= %d bytes\n", SCE_BIGRANGE_T);
5376 VG_(printf)(" 000010 at lock/unlock events\n");
5377 VG_(printf)(" 000001 at thread create/join events\n");
5378 VG_(printf)(
5379 " --vts-pruning=never|auto|always [auto]\n"
5380 " never: is never done (may cause big space leaks in Helgrind)\n"
5381 " auto: done just often enough to keep space usage under control\n"
5382 " always: done after every VTS GC (mostly just a big time waster)\n"
5383 );
5384 }
5385
hg_print_stats(void)5386 static void hg_print_stats (void)
5387 {
5388
5389 if (1) {
5390 VG_(printf)("\n");
5391 HG_(ppWSUstats)( univ_lsets, "univ_lsets" );
5392 if (HG_(clo_track_lockorders)) {
5393 VG_(printf)("\n");
5394 HG_(ppWSUstats)( univ_laog, "univ_laog" );
5395 }
5396 }
5397
5398 //zz VG_(printf)("\n");
5399 //zz VG_(printf)(" hbefore: %'10lu queries\n", stats__hbefore_queries);
5400 //zz VG_(printf)(" hbefore: %'10lu cache 0 hits\n", stats__hbefore_cache0s);
5401 //zz VG_(printf)(" hbefore: %'10lu cache > 0 hits\n", stats__hbefore_cacheNs);
5402 //zz VG_(printf)(" hbefore: %'10lu graph searches\n", stats__hbefore_gsearches);
5403 //zz VG_(printf)(" hbefore: %'10lu of which slow\n",
5404 //zz stats__hbefore_gsearches - stats__hbefore_gsearchFs);
5405 //zz VG_(printf)(" hbefore: %'10lu stack high water mark\n",
5406 //zz stats__hbefore_stk_hwm);
5407 //zz VG_(printf)(" hbefore: %'10lu cache invals\n", stats__hbefore_invals);
5408 //zz VG_(printf)(" hbefore: %'10lu probes\n", stats__hbefore_probes);
5409
5410 VG_(printf)("\n");
5411 VG_(printf)(" locksets: %'8d unique lock sets\n",
5412 (Int)HG_(cardinalityWSU)( univ_lsets ));
5413 if (HG_(clo_track_lockorders)) {
5414 VG_(printf)(" univ_laog: %'8d unique lock sets\n",
5415 (Int)HG_(cardinalityWSU)( univ_laog ));
5416 }
5417
5418 //VG_(printf)("L(ast)L(ock) map: %'8lu inserts (%d map size)\n",
5419 // stats__ga_LL_adds,
5420 // (Int)(ga_to_lastlock ? VG_(sizeFM)( ga_to_lastlock ) : 0) );
5421
5422 VG_(printf)(" LockN-to-P map: %'8llu queries (%llu map size)\n",
5423 HG_(stats__LockN_to_P_queries),
5424 HG_(stats__LockN_to_P_get_map_size)() );
5425
5426 VG_(printf)("client malloc-ed blocks: %'8d\n",
5427 VG_(HT_count_nodes)(hg_mallocmeta_table));
5428
5429 VG_(printf)("string table map: %'8llu queries (%llu map size)\n",
5430 HG_(stats__string_table_queries),
5431 HG_(stats__string_table_get_map_size)() );
5432 if (HG_(clo_track_lockorders)) {
5433 VG_(printf)(" LAOG: %'8d map size\n",
5434 (Int)(laog ? VG_(sizeFM)( laog ) : 0));
5435 VG_(printf)(" LAOG exposition: %'8d map size\n",
5436 (Int)(laog_exposition ? VG_(sizeFM)( laog_exposition ) : 0));
5437 }
5438
5439 VG_(printf)(" locks: %'8lu acquires, "
5440 "%'lu releases\n",
5441 stats__lockN_acquires,
5442 stats__lockN_releases
5443 );
5444 VG_(printf)(" sanity checks: %'8lu\n", stats__sanity_checks);
5445
5446 VG_(printf)("\n");
5447 libhb_shutdown(True); // This in fact only print stats.
5448 }
5449
hg_fini(Int exitcode)5450 static void hg_fini ( Int exitcode )
5451 {
5452 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5453 VG_(message)(Vg_UserMsg,
5454 "For counts of detected and suppressed errors, "
5455 "rerun with: -v\n");
5456 }
5457
5458 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)
5459 && HG_(clo_history_level) >= 2) {
5460 VG_(umsg)(
5461 "Use --history-level=approx or =none to gain increased speed, at\n" );
5462 VG_(umsg)(
5463 "the cost of reduced accuracy of conflicting-access information\n");
5464 }
5465
5466 if (SHOW_DATA_STRUCTURES)
5467 pp_everything( PP_ALL, "SK_(fini)" );
5468 if (HG_(clo_sanity_flags))
5469 all__sanity_check("SK_(fini)");
5470
5471 if (VG_(clo_stats))
5472 hg_print_stats();
5473 }
5474
5475 /* FIXME: move these somewhere sane */
5476
5477 static
for_libhb__get_stacktrace(Thr * hbt,Addr * frames,UWord nRequest)5478 void for_libhb__get_stacktrace ( Thr* hbt, Addr* frames, UWord nRequest )
5479 {
5480 Thread* thr;
5481 ThreadId tid;
5482 UWord nActual;
5483 tl_assert(hbt);
5484 thr = libhb_get_Thr_hgthread( hbt );
5485 tl_assert(thr);
5486 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
5487 nActual = (UWord)VG_(get_StackTrace)( tid, frames, (UInt)nRequest,
5488 NULL, NULL, 0 );
5489 tl_assert(nActual <= nRequest);
5490 for (; nActual < nRequest; nActual++)
5491 frames[nActual] = 0;
5492 }
5493
5494 static
for_libhb__get_EC(Thr * hbt)5495 ExeContext* for_libhb__get_EC ( Thr* hbt )
5496 {
5497 Thread* thr;
5498 ThreadId tid;
5499 ExeContext* ec;
5500 tl_assert(hbt);
5501 thr = libhb_get_Thr_hgthread( hbt );
5502 tl_assert(thr);
5503 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
5504 /* this will assert if tid is invalid */
5505 ec = VG_(record_ExeContext)( tid, 0 );
5506 return ec;
5507 }
5508
5509
hg_post_clo_init(void)5510 static void hg_post_clo_init ( void )
5511 {
5512 Thr* hbthr_root;
5513
5514 /////////////////////////////////////////////
5515 hbthr_root = libhb_init( for_libhb__get_stacktrace,
5516 for_libhb__get_EC );
5517 /////////////////////////////////////////////
5518
5519
5520 if (HG_(clo_track_lockorders))
5521 laog__init();
5522
5523 initialise_data_structures(hbthr_root);
5524 }
5525
hg_info_location(Addr a)5526 static void hg_info_location (Addr a)
5527 {
5528 (void) HG_(get_and_pp_addrdescr) (a);
5529 }
5530
hg_pre_clo_init(void)5531 static void hg_pre_clo_init ( void )
5532 {
5533 VG_(details_name) ("Helgrind");
5534 VG_(details_version) (NULL);
5535 VG_(details_description) ("a thread error detector");
5536 VG_(details_copyright_author)(
5537 "Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.");
5538 VG_(details_bug_reports_to) (VG_BUGS_TO);
5539 VG_(details_avg_translation_sizeB) ( 320 );
5540
5541 VG_(basic_tool_funcs) (hg_post_clo_init,
5542 hg_instrument,
5543 hg_fini);
5544
5545 VG_(needs_core_errors) ();
5546 VG_(needs_tool_errors) (HG_(eq_Error),
5547 HG_(before_pp_Error),
5548 HG_(pp_Error),
5549 False,/*show TIDs for errors*/
5550 HG_(update_extra),
5551 HG_(recognised_suppression),
5552 HG_(read_extra_suppression_info),
5553 HG_(error_matches_suppression),
5554 HG_(get_error_name),
5555 HG_(get_extra_suppression_info),
5556 HG_(print_extra_suppression_use),
5557 HG_(update_extra_suppression_use));
5558
5559 VG_(needs_xml_output) ();
5560
5561 VG_(needs_command_line_options)(hg_process_cmd_line_option,
5562 hg_print_usage,
5563 hg_print_debug_usage);
5564 VG_(needs_client_requests) (hg_handle_client_request);
5565
5566 // FIXME?
5567 //VG_(needs_sanity_checks) (hg_cheap_sanity_check,
5568 // hg_expensive_sanity_check);
5569
5570 VG_(needs_print_stats) (hg_print_stats);
5571 VG_(needs_info_location) (hg_info_location);
5572
5573 VG_(needs_malloc_replacement) (hg_cli__malloc,
5574 hg_cli____builtin_new,
5575 hg_cli____builtin_vec_new,
5576 hg_cli__memalign,
5577 hg_cli__calloc,
5578 hg_cli__free,
5579 hg_cli____builtin_delete,
5580 hg_cli____builtin_vec_delete,
5581 hg_cli__realloc,
5582 hg_cli_malloc_usable_size,
5583 HG_CLI__DEFAULT_MALLOC_REDZONE_SZB );
5584
5585 /* 21 Dec 08: disabled this; it mostly causes H to start more
5586 slowly and use significantly more memory, without very often
5587 providing useful results. The user can request to load this
5588 information manually with --read-var-info=yes. */
5589 if (0) VG_(needs_var_info)(); /* optional */
5590
5591 VG_(track_new_mem_startup) ( evh__new_mem_w_perms );
5592 VG_(track_new_mem_stack_signal)( evh__new_mem_w_tid );
5593 VG_(track_new_mem_brk) ( evh__new_mem_w_tid );
5594 VG_(track_new_mem_mmap) ( evh__new_mem_w_perms );
5595 VG_(track_new_mem_stack) ( evh__new_mem_stack );
5596
5597 // FIXME: surely this isn't thread-aware
5598 VG_(track_copy_mem_remap) ( evh__copy_mem );
5599
5600 VG_(track_change_mem_mprotect) ( evh__set_perms );
5601
5602 VG_(track_die_mem_stack_signal)( evh__die_mem );
5603 VG_(track_die_mem_brk) ( evh__die_mem_munmap );
5604 VG_(track_die_mem_munmap) ( evh__die_mem_munmap );
5605
5606 /* evh__die_mem calls at the end libhb_srange_noaccess_NoFX
5607 which has no effect. We do not use VG_(track_die_mem_stack),
5608 as this would be an expensive way to do nothing. */
5609 // VG_(track_die_mem_stack) ( evh__die_mem );
5610
5611 // FIXME: what is this for?
5612 VG_(track_ban_mem_stack) (NULL);
5613
5614 VG_(track_pre_mem_read) ( evh__pre_mem_read );
5615 VG_(track_pre_mem_read_asciiz) ( evh__pre_mem_read_asciiz );
5616 VG_(track_pre_mem_write) ( evh__pre_mem_write );
5617 VG_(track_post_mem_write) (NULL);
5618
5619 /////////////////
5620
5621 VG_(track_pre_thread_ll_create)( evh__pre_thread_ll_create );
5622 VG_(track_pre_thread_ll_exit) ( evh__pre_thread_ll_exit );
5623
5624 VG_(track_start_client_code)( evh__start_client_code );
5625 VG_(track_stop_client_code)( evh__stop_client_code );
5626
5627 /* Ensure that requirements for "dodgy C-as-C++ style inheritance"
5628 as described in comments at the top of pub_tool_hashtable.h, are
5629 met. Blargh. */
5630 tl_assert( sizeof(void*) == sizeof(struct _MallocMeta*) );
5631 tl_assert( sizeof(UWord) == sizeof(Addr) );
5632 hg_mallocmeta_table
5633 = VG_(HT_construct)( "hg_malloc_metadata_table" );
5634
5635 MallocMeta_poolalloc = VG_(newPA) ( sizeof(MallocMeta),
5636 1000,
5637 HG_(zalloc),
5638 "hg_malloc_metadata_pool",
5639 HG_(free));
5640
5641 // add a callback to clean up on (threaded) fork.
5642 VG_(atfork)(NULL/*pre*/, NULL/*parent*/, evh__atfork_child/*child*/);
5643 }
5644
5645 VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
5646
5647 /*--------------------------------------------------------------------*/
5648 /*--- end hg_main.c ---*/
5649 /*--------------------------------------------------------------------*/
5650