1 /* -*- mode: C; c-basic-offset: 3; -*- */ 2 /* 3 This file is part of drd, a thread error detector. 4 5 Copyright (C) 2006-2010 Bart Van Assche <bvanassche (at) acm.org>. 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the 10 License, or (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 20 02111-1307, USA. 21 22 The GNU General Public License is contained in the file COPYING. 23 */ 24 25 26 #include "drd_clientobj.h" /* struct mutex_info */ 27 #include "drd_error.h" 28 #include "drd_malloc_wrappers.h" 29 #include "drd_mutex.h" 30 #include "drd_suppression.h" /* drd_start_suppression() */ 31 #include "pub_drd_bitmap.h" /* LHS_W, ... */ 32 #include "pub_tool_vki.h" 33 #include "pub_tool_basics.h" 34 #include "pub_tool_libcassert.h" /* tl_assert() */ 35 #include "pub_tool_libcbase.h" /* strlen() */ 36 #include "pub_tool_libcfile.h" /* VG_(get_startup_wd)() */ 37 #include "pub_tool_libcprint.h" /* VG_(printf)() */ 38 #include "pub_tool_machine.h" 39 #include "pub_tool_mallocfree.h" /* VG_(malloc), VG_(free) */ 40 #include "pub_tool_threadstate.h" /* VG_(get_pthread_id)() */ 41 #include "pub_tool_tooliface.h" /* VG_(needs_tool_errors)() */ 42 43 44 /* Local variables. */ 45 46 static Bool s_show_conflicting_segments = True; 47 48 49 void DRD_(set_show_conflicting_segments)(const Bool scs) 50 { 51 s_show_conflicting_segments = scs; 52 } 53 54 /** 55 * Describe the client address a as good as possible, putting the result in ai. 56 */ 57 static 58 void describe_malloced_addr(Addr const a, AddrInfo* const ai) 59 { 60 Addr heap_block_start; 61 62 if (DRD_(heap_addrinfo)(a, &heap_block_start, &ai->size, &ai->lastchange)) 63 { 64 ai->akind = eMallocd; 65 ai->rwoffset = a - heap_block_start; 66 } 67 else 68 { 69 ai->akind = eUnknown; 70 } 71 } 72 73 /** 74 * Report where a client synchronization object has been observed for the first 75 * time. The printed call stack will either refer to a pthread_*_init() or a 76 * pthread_*lock() call. 77 */ 78 static void first_observed(const Addr obj) 79 { 80 DrdClientobj* cl; 81 82 cl = DRD_(clientobj_get_any)(obj); 83 if (cl) 84 { 85 tl_assert(cl->any.first_observed_at); 86 VG_(message)(Vg_UserMsg, 87 "%s 0x%lx was first observed at:\n", 88 DRD_(clientobj_type_name)(cl->any.type), 89 obj); 90 VG_(pp_ExeContext)(cl->any.first_observed_at); 91 } 92 } 93 94 static 95 void drd_report_data_race(Error* const err, const DataRaceErrInfo* const dri) 96 { 97 AddrInfo ai; 98 99 XArray* /* of HChar */ descr1 100 = VG_(newXA)( VG_(malloc), "drd.error.drdr2.1", 101 VG_(free), sizeof(HChar) ); 102 XArray* /* of HChar */ descr2 103 = VG_(newXA)( VG_(malloc), "drd.error.drdr2.2", 104 VG_(free), sizeof(HChar) ); 105 106 tl_assert(dri); 107 tl_assert(dri->addr); 108 tl_assert(dri->size > 0); 109 tl_assert(descr1); 110 tl_assert(descr2); 111 112 (void) VG_(get_data_description)(descr1, descr2, dri->addr); 113 /* If there's nothing in descr1/2, free them. Why is it safe to to 114 VG_(indexXA) at zero here? Because VG_(get_data_description) 115 guarantees to zero terminate descr1/2 regardless of the outcome 116 of the call. So there's always at least one element in each XA 117 after the call. 118 */ 119 if (0 == VG_(strlen)( VG_(indexXA)( descr1, 0 ))) { 120 VG_(deleteXA)( descr1 ); 121 descr1 = NULL; 122 } 123 if (0 == VG_(strlen)( VG_(indexXA)( descr2, 0 ))) { 124 VG_(deleteXA)( descr2 ); 125 descr2 = NULL; 126 } 127 /* Assume (assert) that VG_(get_data_description) fills in descr1 128 before it fills in descr2 */ 129 if (descr1 == NULL) 130 tl_assert(descr2 == NULL); 131 /* So anyway. Do we have something useful? */ 132 if (descr1 == NULL) 133 { 134 /* No. Do Plan B. */ 135 describe_malloced_addr(dri->addr, &ai); 136 } 137 VG_(message)(Vg_UserMsg, 138 "Conflicting %s by thread %d at 0x%08lx size %ld\n", 139 dri->access_type == eStore ? "store" : "load", 140 dri->tid, 141 dri->addr, 142 dri->size); 143 VG_(pp_ExeContext)(VG_(get_error_where)(err)); 144 if (descr1 != NULL) 145 { 146 VG_(message)(Vg_UserMsg, "%s\n", (HChar*)VG_(indexXA)(descr1, 0)); 147 if (descr2 != NULL) 148 VG_(message)(Vg_UserMsg, "%s\n", (HChar*)VG_(indexXA)(descr2, 0)); 149 } 150 else if (ai.akind == eMallocd && ai.lastchange) 151 { 152 VG_(message)(Vg_UserMsg, 153 "Address 0x%lx is at offset %ld from 0x%lx." 154 " Allocation context:\n", 155 dri->addr, ai.rwoffset, dri->addr - ai.rwoffset); 156 VG_(pp_ExeContext)(ai.lastchange); 157 } 158 else 159 { 160 char sect_name[64]; 161 VgSectKind sect_kind; 162 163 sect_kind = VG_(DebugInfo_sect_kind)(sect_name, sizeof(sect_name), 164 dri->addr); 165 if (sect_kind != Vg_SectUnknown) 166 { 167 VG_(message)(Vg_UserMsg, 168 "Allocation context: %s section of %s\n", 169 VG_(pp_SectKind)(sect_kind), 170 sect_name); 171 } 172 else 173 { 174 VG_(message)(Vg_UserMsg, "Allocation context: unknown.\n"); 175 } 176 } 177 if (s_show_conflicting_segments) 178 { 179 DRD_(thread_report_conflicting_segments)(dri->tid, 180 dri->addr, dri->size, 181 dri->access_type); 182 } 183 184 if (descr2) 185 VG_(deleteXA)(descr2); 186 if (descr1) 187 VG_(deleteXA)(descr1); 188 } 189 190 /** 191 * Compare two error contexts. The core function VG_(maybe_record_error)() 192 * calls this function to compare error contexts such that errors that occur 193 * repeatedly are only printed once. This function is only called by the core 194 * if the error kind of e1 and e2 matches and if the ExeContext's of e1 and 195 * e2 also match. 196 */ 197 static Bool drd_compare_error_contexts(VgRes res, Error* e1, Error* e2) 198 { 199 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2)); 200 201 switch (VG_(get_error_kind)(e1)) 202 { 203 case DataRaceErr: 204 { 205 const DataRaceErrInfo* const dri1 = VG_(get_error_extra)(e1); 206 const DataRaceErrInfo* const dri2 = VG_(get_error_extra)(e2); 207 return dri1->access_type == dri2->access_type 208 && dri1->size == dri2->size; 209 } 210 case MutexErr: 211 { 212 const MutexErrInfo* const mei1 = VG_(get_error_extra)(e1); 213 const MutexErrInfo* const mei2 = VG_(get_error_extra)(e2); 214 return mei1->mutex == mei2->mutex; 215 } 216 default: 217 return True; 218 } 219 } 220 221 /** 222 * Called by the core just before an error message will be printed. Used by 223 * DRD to print the thread number as a preamble. 224 */ 225 static void drd_tool_error_before_pp(Error* const e) 226 { 227 static DrdThreadId s_last_tid_printed = 1; 228 DrdThreadId* err_extra; 229 230 err_extra = VG_(get_error_extra)(e); 231 232 if (err_extra && *err_extra != s_last_tid_printed) 233 { 234 VG_(umsg)("%s:\n", DRD_(thread_get_name)(*err_extra)); 235 s_last_tid_printed = *err_extra; 236 } 237 } 238 239 /** Report an error to the user. */ 240 static void drd_tool_error_pp(Error* const e) 241 { 242 switch (VG_(get_error_kind)(e)) 243 { 244 case DataRaceErr: { 245 drd_report_data_race(e, VG_(get_error_extra)(e)); 246 break; 247 } 248 case MutexErr: { 249 MutexErrInfo* p = (MutexErrInfo*)(VG_(get_error_extra)(e)); 250 tl_assert(p); 251 if (p->recursion_count >= 0) 252 { 253 VG_(message)(Vg_UserMsg, 254 "%s: mutex 0x%lx, recursion count %d, owner %d.\n", 255 VG_(get_error_string)(e), 256 p->mutex, 257 p->recursion_count, 258 p->owner); 259 } 260 else 261 { 262 VG_(message)(Vg_UserMsg, 263 "The object at address 0x%lx is not a mutex.\n", 264 p->mutex); 265 } 266 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 267 first_observed(p->mutex); 268 break; 269 } 270 case CondErr: { 271 CondErrInfo* cdei =(CondErrInfo*)(VG_(get_error_extra)(e)); 272 VG_(message)(Vg_UserMsg, 273 "%s: cond 0x%lx\n", 274 VG_(get_error_string)(e), 275 cdei->cond); 276 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 277 first_observed(cdei->cond); 278 break; 279 } 280 case CondDestrErr: { 281 CondDestrErrInfo* cdi = (CondDestrErrInfo*)(VG_(get_error_extra)(e)); 282 VG_(message)(Vg_UserMsg, 283 "%s: cond 0x%lx, mutex 0x%lx locked by thread %d\n", 284 VG_(get_error_string)(e), 285 cdi->cond, cdi->mutex, 286 cdi->owner); 287 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 288 first_observed(cdi->mutex); 289 break; 290 } 291 case CondRaceErr: { 292 CondRaceErrInfo* cei = (CondRaceErrInfo*)(VG_(get_error_extra)(e)); 293 VG_(message)(Vg_UserMsg, 294 "Probably a race condition: condition variable 0x%lx has" 295 " been signaled but the associated mutex 0x%lx is not" 296 " locked by the signalling thread.\n", 297 cei->cond, cei->mutex); 298 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 299 first_observed(cei->cond); 300 first_observed(cei->mutex); 301 break; 302 } 303 case CondWaitErr: { 304 CondWaitErrInfo* cwei = (CondWaitErrInfo*)(VG_(get_error_extra)(e)); 305 VG_(message)(Vg_UserMsg, 306 "%s: condition variable 0x%lx, mutexes 0x%lx and 0x%lx\n", 307 VG_(get_error_string)(e), 308 cwei->cond, 309 cwei->mutex1, 310 cwei->mutex2); 311 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 312 first_observed(cwei->cond); 313 first_observed(cwei->mutex1); 314 first_observed(cwei->mutex2); 315 break; 316 } 317 case SemaphoreErr: { 318 SemaphoreErrInfo* sei = (SemaphoreErrInfo*)(VG_(get_error_extra)(e)); 319 tl_assert(sei); 320 VG_(message)(Vg_UserMsg, 321 "%s: semaphore 0x%lx\n", 322 VG_(get_error_string)(e), 323 sei->semaphore); 324 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 325 first_observed(sei->semaphore); 326 break; 327 } 328 case BarrierErr: { 329 BarrierErrInfo* bei = (BarrierErrInfo*)(VG_(get_error_extra)(e)); 330 tl_assert(bei); 331 VG_(message)(Vg_UserMsg, 332 "%s: barrier 0x%lx\n", 333 VG_(get_error_string)(e), 334 bei->barrier); 335 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 336 if (bei->other_context) 337 { 338 VG_(message)(Vg_UserMsg, 339 "Conflicting wait call by thread %d:\n", 340 bei->other_tid); 341 VG_(pp_ExeContext)(bei->other_context); 342 } 343 first_observed(bei->barrier); 344 break; 345 } 346 case RwlockErr: { 347 RwlockErrInfo* p = (RwlockErrInfo*)(VG_(get_error_extra)(e)); 348 tl_assert(p); 349 VG_(message)(Vg_UserMsg, 350 "%s: rwlock 0x%lx.\n", 351 VG_(get_error_string)(e), 352 p->rwlock); 353 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 354 first_observed(p->rwlock); 355 break; 356 } 357 case HoldtimeErr: { 358 HoldtimeErrInfo* p =(HoldtimeErrInfo*)(VG_(get_error_extra)(e)); 359 tl_assert(p); 360 tl_assert(p->acquired_at); 361 VG_(message)(Vg_UserMsg, "Acquired at:\n"); 362 VG_(pp_ExeContext)(p->acquired_at); 363 VG_(message)(Vg_UserMsg, 364 "Lock on %s 0x%lx was held during %d ms (threshold: %d ms).\n", 365 VG_(get_error_string)(e), 366 p->synchronization_object, 367 p->hold_time_ms, 368 p->threshold_ms); 369 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 370 first_observed(p->synchronization_object); 371 break; 372 } 373 case GenericErr: { 374 GenericErrInfo* gei = (GenericErrInfo*)(VG_(get_error_extra)(e)); 375 VG_(message)(Vg_UserMsg, "%s\n", VG_(get_error_string)(e)); 376 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 377 if (gei->addr) 378 first_observed(gei->addr); 379 break; 380 } 381 case InvalidThreadId: { 382 InvalidThreadIdInfo* iti =(InvalidThreadIdInfo*)(VG_(get_error_extra)(e)); 383 VG_(message)(Vg_UserMsg, 384 "%s 0x%llx\n", VG_(get_error_string)(e), iti->ptid); 385 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 386 break; 387 } 388 case UnimpHgClReq: { 389 UnimpClReqInfo* uicr =(UnimpClReqInfo*)(VG_(get_error_extra)(e)); 390 VG_(message)(Vg_UserMsg, 391 "The annotation macro %s has not yet been implemented in" 392 " <valgrind/helgrind.h>\n", 393 /*VG_(get_error_string)(e),*/ uicr->descr); 394 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 395 break; 396 } 397 case UnimpDrdClReq: { 398 UnimpClReqInfo* uicr =(UnimpClReqInfo*)(VG_(get_error_extra)(e)); 399 VG_(message)(Vg_UserMsg, 400 "The annotation macro %s has not yet been implemented in" 401 " <valgrind/drd.h>\n", 402 uicr->descr); 403 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 404 break; 405 } 406 default: 407 VG_(message)(Vg_UserMsg, 408 "%s\n", 409 VG_(get_error_string)(e)); 410 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 411 break; 412 } 413 } 414 415 static UInt drd_tool_error_update_extra(Error* e) 416 { 417 switch (VG_(get_error_kind)(e)) 418 { 419 case DataRaceErr: 420 return sizeof(DataRaceErrInfo); 421 case MutexErr: 422 return sizeof(MutexErrInfo); 423 case CondErr: 424 return sizeof(CondErrInfo); 425 case CondDestrErr: 426 return sizeof(CondDestrErrInfo); 427 case CondRaceErr: 428 return sizeof(CondRaceErrInfo); 429 case CondWaitErr: 430 return sizeof(CondWaitErrInfo); 431 case SemaphoreErr: 432 return sizeof(SemaphoreErrInfo); 433 case BarrierErr: 434 return sizeof(BarrierErrInfo); 435 case RwlockErr: 436 return sizeof(RwlockErrInfo); 437 case HoldtimeErr: 438 return sizeof(HoldtimeErrInfo); 439 case GenericErr: 440 return sizeof(GenericErrInfo); 441 case InvalidThreadId: 442 return sizeof(InvalidThreadIdInfo); 443 case UnimpHgClReq: 444 return sizeof(UnimpClReqInfo); 445 case UnimpDrdClReq: 446 return sizeof(UnimpClReqInfo); 447 default: 448 tl_assert(False); 449 break; 450 } 451 } 452 453 /** 454 * Parse suppression name. 455 * 456 * The suppression types recognized by DRD are the same types as the error 457 * types supported by DRD. So try to match the suppression name against the 458 * names of DRD error types. 459 */ 460 static Bool drd_is_recognized_suppression(Char* const name, Supp* const supp) 461 { 462 DrdErrorKind skind = 0; 463 464 if (VG_(strcmp)(name, STR_DataRaceErr) == 0) 465 skind = DataRaceErr; 466 else if (VG_(strcmp)(name, STR_MutexErr) == 0) 467 skind = MutexErr; 468 else if (VG_(strcmp)(name, STR_CondErr) == 0) 469 skind = CondErr; 470 else if (VG_(strcmp)(name, STR_CondDestrErr) == 0) 471 skind = CondDestrErr; 472 else if (VG_(strcmp)(name, STR_CondRaceErr) == 0) 473 skind = CondRaceErr; 474 else if (VG_(strcmp)(name, STR_CondWaitErr) == 0) 475 skind = CondWaitErr; 476 else if (VG_(strcmp)(name, STR_SemaphoreErr) == 0) 477 skind = SemaphoreErr; 478 else if (VG_(strcmp)(name, STR_BarrierErr) == 0) 479 skind = BarrierErr; 480 else if (VG_(strcmp)(name, STR_RwlockErr) == 0) 481 skind = RwlockErr; 482 else if (VG_(strcmp)(name, STR_HoldtimeErr) == 0) 483 skind = HoldtimeErr; 484 else if (VG_(strcmp)(name, STR_GenericErr) == 0) 485 skind = GenericErr; 486 else if (VG_(strcmp)(name, STR_InvalidThreadId) == 0) 487 skind = InvalidThreadId; 488 else if (VG_(strcmp)(name, STR_UnimpHgClReq) == 0) 489 skind = UnimpHgClReq; 490 else if (VG_(strcmp)(name, STR_UnimpDrdClReq) == 0) 491 skind = UnimpDrdClReq; 492 else 493 return False; 494 495 VG_(set_supp_kind)(supp, skind); 496 return True; 497 } 498 499 /** 500 * Read additional suppression information from the suppression file. 501 * 502 * None of the suppression patterns recognized by DRD has 'extra' lines 503 * of information in the suppression file, so just return True to indicate 504 * that reading the 'extra' lines succeeded. 505 */ 506 static 507 Bool drd_read_extra_suppression_info(Int fd, Char** bufpp, 508 SizeT* nBufp, Supp* supp) 509 { 510 return True; 511 } 512 513 /** 514 * Determine whether or not the types of the given error message and the 515 * given suppression match. 516 */ 517 static Bool drd_error_matches_suppression(Error* const e, Supp* const supp) 518 { 519 return VG_(get_supp_kind)(supp) == VG_(get_error_kind)(e); 520 } 521 522 static Char* drd_get_error_name(Error* e) 523 { 524 switch (VG_(get_error_kind)(e)) 525 { 526 case DataRaceErr: return VGAPPEND(STR_, DataRaceErr); 527 case MutexErr: return VGAPPEND(STR_, MutexErr); 528 case CondErr: return VGAPPEND(STR_, CondErr); 529 case CondDestrErr: return VGAPPEND(STR_, CondDestrErr); 530 case CondRaceErr: return VGAPPEND(STR_, CondRaceErr); 531 case CondWaitErr: return VGAPPEND(STR_, CondWaitErr); 532 case SemaphoreErr: return VGAPPEND(STR_, SemaphoreErr); 533 case BarrierErr: return VGAPPEND(STR_, BarrierErr); 534 case RwlockErr: return VGAPPEND(STR_, RwlockErr); 535 case HoldtimeErr: return VGAPPEND(STR_, HoldtimeErr); 536 case GenericErr: return VGAPPEND(STR_, GenericErr); 537 case InvalidThreadId: return VGAPPEND(STR_, InvalidThreadId); 538 case UnimpHgClReq: return VGAPPEND(STR_, UnimpHgClReq); 539 case UnimpDrdClReq: return VGAPPEND(STR_, UnimpDrdClReq); 540 default: 541 tl_assert(0); 542 } 543 return 0; 544 } 545 546 /** 547 * Return extra suppression information. 548 * 549 * Invoked while printing a suppression pattern because the user 550 * specified --gen-suppressions=yes or all on the command line. DRD does not 551 * define any 'extra' suppression information. 552 */ 553 static 554 Bool drd_get_extra_suppression_info(Error* e, 555 /*OUT*/Char* buf, Int nBuf) 556 { 557 return False; 558 } 559 560 /** Tell the Valgrind core about DRD's error handlers. */ 561 void DRD_(register_error_handlers)(void) 562 { 563 VG_(needs_tool_errors)(drd_compare_error_contexts, 564 drd_tool_error_before_pp, 565 drd_tool_error_pp, 566 False, 567 drd_tool_error_update_extra, 568 drd_is_recognized_suppression, 569 drd_read_extra_suppression_info, 570 drd_error_matches_suppression, 571 drd_get_error_name, 572 drd_get_extra_suppression_info); 573 } 574