1 2 /*--------------------------------------------------------------------*/ 3 /*--- Management of error messages. m_errormgr.c ---*/ 4 /*--------------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2000-2010 Julian Seward 11 jseward (at) acm.org 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26 02111-1307, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29 */ 30 31 #include "pub_core_basics.h" 32 #include "pub_core_vki.h" 33 #include "pub_core_threadstate.h" // For VG_N_THREADS 34 #include "pub_core_debugger.h" 35 #include "pub_core_debuginfo.h" 36 #include "pub_core_errormgr.h" 37 #include "pub_core_execontext.h" 38 #include "pub_core_libcbase.h" 39 #include "pub_core_libcassert.h" 40 #include "pub_core_libcfile.h" 41 #include "pub_core_libcprint.h" 42 #include "pub_core_libcproc.h" // For VG_(getpid)() 43 #include "pub_core_seqmatch.h" 44 #include "pub_core_mallocfree.h" 45 #include "pub_core_options.h" 46 #include "pub_core_stacktrace.h" 47 #include "pub_core_tooliface.h" 48 #include "pub_core_translate.h" // for VG_(translate)() 49 #include "pub_core_xarray.h" // VG_(xaprintf) et al 50 51 /*------------------------------------------------------------*/ 52 /*--- Globals ---*/ 53 /*------------------------------------------------------------*/ 54 55 /* After this many different unsuppressed errors have been observed, 56 be more conservative about collecting new ones. */ 57 #define M_COLLECT_ERRORS_SLOWLY_AFTER 100 58 59 /* After this many different unsuppressed errors have been observed, 60 stop collecting errors at all, and tell the user their program is 61 evidently a steaming pile of camel dung. */ 62 #define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000 63 64 /* After this many total errors have been observed, stop collecting 65 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */ 66 #define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000 67 68 /* The list of error contexts found, both suppressed and unsuppressed. 69 Initially empty, and grows as errors are detected. */ 70 static Error* errors = NULL; 71 72 /* The list of suppression directives, as read from the specified 73 suppressions file. Note that the list gets rearranged as a result 74 of the searches done by is_suppressible_error(). */ 75 static Supp* suppressions = NULL; 76 77 /* Running count of unsuppressed errors detected. */ 78 static UInt n_errs_found = 0; 79 80 /* Running count of suppressed errors detected. */ 81 static UInt n_errs_suppressed = 0; 82 83 /* Running count of unsuppressed error contexts. */ 84 static UInt n_err_contexts = 0; 85 86 /* Running count of suppressed error contexts. */ 87 static UInt n_supp_contexts = 0; 88 89 90 /* forwards ... */ 91 static Supp* is_suppressible_error ( Error* err ); 92 93 static ThreadId last_tid_printed = 1; 94 95 /* Stats: number of searches of the error list initiated. */ 96 static UWord em_errlist_searches = 0; 97 98 /* Stats: number of comparisons done during error list 99 searching. */ 100 static UWord em_errlist_cmps = 0; 101 102 /* Stats: number of searches of the suppression list initiated. */ 103 static UWord em_supplist_searches = 0; 104 105 /* Stats: number of comparisons done during suppression list 106 searching. */ 107 static UWord em_supplist_cmps = 0; 108 109 /*------------------------------------------------------------*/ 110 /*--- Error type ---*/ 111 /*------------------------------------------------------------*/ 112 113 /* Errors. Extensible (via the 'extra' field). Tools can use a normal 114 enum (with element values in the normal range (0..)) for 'ekind'. 115 Functions for getting/setting the tool-relevant fields are in 116 include/pub_tool_errormgr.h. 117 118 When errors are found and recorded with VG_(maybe_record_error)(), all 119 the tool must do is pass in the four parameters; core will 120 allocate/initialise the error record. 121 */ 122 struct _Error { 123 struct _Error* next; 124 // Unique tag. This gives the error a unique identity (handle) by 125 // which it can be referred to afterwords. Currently only used for 126 // XML printing. 127 UInt unique; 128 // NULL if unsuppressed; or ptr to suppression record. 129 Supp* supp; 130 Int count; 131 132 // The tool-specific part 133 ThreadId tid; // Initialised by core 134 ExeContext* where; // Initialised by core 135 ErrorKind ekind; // Used by ALL. Must be in the range (0..) 136 Addr addr; // Used frequently 137 Char* string; // Used frequently 138 void* extra; // For any tool-specific extras 139 }; 140 141 142 ExeContext* VG_(get_error_where) ( Error* err ) 143 { 144 return err->where; 145 } 146 147 ErrorKind VG_(get_error_kind) ( Error* err ) 148 { 149 return err->ekind; 150 } 151 152 Addr VG_(get_error_address) ( Error* err ) 153 { 154 return err->addr; 155 } 156 157 Char* VG_(get_error_string) ( Error* err ) 158 { 159 return err->string; 160 } 161 162 void* VG_(get_error_extra) ( Error* err ) 163 { 164 return err->extra; 165 } 166 167 UInt VG_(get_n_errs_found)( void ) 168 { 169 return n_errs_found; 170 } 171 172 /*------------------------------------------------------------*/ 173 /*--- Suppression type ---*/ 174 /*------------------------------------------------------------*/ 175 176 /* Note: it is imperative this doesn't overlap with (0..) at all, as tools 177 * effectively extend it by defining their own enums in the (0..) range. */ 178 typedef 179 enum { 180 // Nb: thread errors are a relic of the time when Valgrind's core 181 // could detect them. This example is left commented-out as an 182 // example should new core errors ever be added. 183 ThreadSupp = -1, /* Matches ThreadErr */ 184 } 185 CoreSuppKind; 186 187 /* Max number of callers for context in a suppression. */ 188 #define VG_MAX_SUPP_CALLERS 24 189 190 /* For each caller specified for a suppression, record the nature of 191 the caller name. Not of interest to tools. */ 192 typedef 193 enum { 194 NoName, /* Error case */ 195 ObjName, /* Name is of an shared object file. */ 196 FunName, /* Name is of a function. */ 197 DotDotDot /* Frame-level wildcard */ 198 } 199 SuppLocTy; 200 201 typedef 202 struct { 203 SuppLocTy ty; 204 Char* name; /* NULL for NoName and DotDotDot */ 205 } 206 SuppLoc; 207 208 /* Suppressions. Tools can get/set tool-relevant parts with functions 209 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field. 210 Tools can use a normal enum (with element values in the normal range 211 (0..)) for 'skind'. */ 212 struct _Supp { 213 struct _Supp* next; 214 Int count; // The number of times this error has been suppressed. 215 Char* sname; // The name by which the suppression is referred to. 216 217 // Length of 'callers' 218 Int n_callers; 219 // Array of callers, for matching stack traces. First one (name of fn 220 // where err occurs) is mandatory; rest are optional. 221 SuppLoc* callers; 222 223 /* The tool-specific part */ 224 SuppKind skind; // What kind of suppression. Must use the range (0..). 225 Char* string; // String -- use is optional. NULL by default. 226 void* extra; // Anything else -- use is optional. NULL by default. 227 }; 228 229 SuppKind VG_(get_supp_kind) ( Supp* su ) 230 { 231 return su->skind; 232 } 233 234 Char* VG_(get_supp_string) ( Supp* su ) 235 { 236 return su->string; 237 } 238 239 void* VG_(get_supp_extra) ( Supp* su ) 240 { 241 return su->extra; 242 } 243 244 245 void VG_(set_supp_kind) ( Supp* su, SuppKind skind ) 246 { 247 su->skind = skind; 248 } 249 250 void VG_(set_supp_string) ( Supp* su, Char* string ) 251 { 252 su->string = string; 253 } 254 255 void VG_(set_supp_extra) ( Supp* su, void* extra ) 256 { 257 su->extra = extra; 258 } 259 260 261 /*------------------------------------------------------------*/ 262 /*--- Helper fns ---*/ 263 /*------------------------------------------------------------*/ 264 265 // Only show core errors if the tool wants to, we're not running with -q, 266 // and were not outputting XML. 267 Bool VG_(showing_core_errors)(void) 268 { 269 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml); 270 } 271 272 /* Compare errors, to detect duplicates. 273 */ 274 static Bool eq_Error ( VgRes res, Error* e1, Error* e2 ) 275 { 276 if (e1->ekind != e2->ekind) 277 return False; 278 if (!VG_(eq_ExeContext)(res, e1->where, e2->where)) 279 return False; 280 281 switch (e1->ekind) { 282 //(example code, see comment on CoreSuppKind above) 283 //case ThreadErr: 284 // vg_assert(VG_(needs).core_errors); 285 // return <something> 286 default: 287 if (VG_(needs).tool_errors) { 288 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2); 289 } else { 290 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n" 291 "probably needs to be set.\n", 292 e1->ekind); 293 VG_(tool_panic)("unhandled error type"); 294 } 295 } 296 } 297 298 299 /* Helper functions for suppression generation: print a single line of 300 a suppression pseudo-stack-trace, either in XML or text mode. It's 301 important that the behaviour of these two functions exactly 302 corresponds. 303 */ 304 #define ERRTXT_LEN 4096 305 306 static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque) 307 { 308 static UChar buf[ERRTXT_LEN]; 309 if ( VG_(get_fnname_no_cxx_demangle) (ip, buf, ERRTXT_LEN) ) { 310 VG_(printf_xml_no_f_c)(" <sframe> <fun>%t</fun> </sframe>\n", buf); 311 } else 312 if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) { 313 VG_(printf_xml_no_f_c)(" <sframe> <obj>%t</obj> </sframe>\n", buf); 314 } else { 315 VG_(printf_xml_no_f_c)(" <sframe> <obj>*</obj> </sframe>\n"); 316 } 317 } 318 319 static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV) 320 { 321 static UChar buf[ERRTXT_LEN]; 322 XArray* /* of HChar */ text = (XArray*)textV; 323 if ( VG_(get_fnname_no_cxx_demangle) (ip, buf, ERRTXT_LEN) ) { 324 VG_(xaprintf)(text, " fun:%s\n", buf); 325 } else 326 if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) { 327 VG_(xaprintf)(text, " obj:%s\n", buf); 328 } else { 329 VG_(xaprintf)(text, " obj:*\n"); 330 } 331 } 332 333 /* Generate a suppression for an error, either in text or XML mode. 334 */ 335 static void gen_suppression(Error* err) 336 { 337 Char xtra[256]; /* assumed big enough (is overrun-safe) */ 338 Bool anyXtra; 339 Char* name; 340 ExeContext* ec; 341 XArray* /* HChar */ text; 342 343 const HChar* dummy_name = "insert_a_suppression_name_here"; 344 345 vg_assert(err); 346 347 /* In XML mode, we also need to print the plain text version of the 348 suppresion in a CDATA section. What that really means is, we 349 need to generate the plaintext version both in XML and text 350 mode. So generate it into TEXT. */ 351 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1", 352 VG_(free), sizeof(HChar) ); 353 vg_assert(text); 354 355 ec = VG_(get_error_where)(err); 356 vg_assert(ec); 357 358 name = VG_TDICT_CALL(tool_get_error_name, err); 359 if (NULL == name) { 360 VG_(umsg)("(%s does not allow error to be suppressed)\n", 361 VG_(details).name); 362 return; 363 } 364 365 /* Ok. Generate the plain text version into TEXT. */ 366 VG_(xaprintf)(text, "{\n"); 367 VG_(xaprintf)(text, " <%s>\n", dummy_name); 368 VG_(xaprintf)(text, " %s:%s\n", VG_(details).name, name); 369 370 VG_(memset)(xtra, 0, sizeof(xtra)); 371 anyXtra = VG_TDICT_CALL(tool_get_extra_suppression_info, 372 err, xtra, sizeof(xtra)); 373 vg_assert(xtra[sizeof(xtra)-1] == 0); 374 375 if (anyXtra) 376 VG_(xaprintf)(text, " %s\n", xtra); 377 378 // Print stack trace elements 379 UInt n_ips = VG_(get_ExeContext_n_ips)(ec); 380 tl_assert(n_ips > 0); 381 if (n_ips > VG_MAX_SUPP_CALLERS) 382 n_ips = VG_MAX_SUPP_CALLERS; 383 VG_(apply_StackTrace)(printSuppForIp_nonXML, 384 text, 385 VG_(get_ExeContext_StackTrace)(ec), 386 n_ips); 387 388 VG_(xaprintf)(text, "}\n"); 389 // zero terminate 390 VG_(xaprintf)(text, "%c", (HChar)0 ); 391 // VG_(printf) of text 392 393 /* And now display it. */ 394 if (! VG_(clo_xml) ) { 395 396 // the simple case 397 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) ); 398 399 } else { 400 401 /* Now we have to print the XML directly. No need to go to the 402 effort of stuffing it in an XArray, since we won't need it 403 again. */ 404 VG_(printf_xml)(" <suppression>\n"); 405 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name); 406 VG_(printf_xml_no_f_c)( 407 " <skind>%t:%t</skind>\n", VG_(details).name, name); 408 if (anyXtra) 409 VG_(printf_xml_no_f_c)(" <skaux>%t</skaux>\n", xtra); 410 411 // Print stack trace elements 412 VG_(apply_StackTrace)(printSuppForIp_XML, 413 NULL, 414 VG_(get_ExeContext_StackTrace)(ec), 415 VG_(get_ExeContext_n_ips)(ec)); 416 417 // And now the cdata bit 418 // XXX FIXME! properly handle the case where the raw text 419 // itself contains "]]>", as specified in Protocol 4. 420 VG_(printf_xml)(" <rawtext>\n"); 421 VG_(printf_xml)("<![CDATA[\n"); 422 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) ); 423 VG_(printf_xml)("]]>\n"); 424 VG_(printf_xml)(" </rawtext>\n"); 425 VG_(printf_xml)(" </suppression>\n"); 426 427 } 428 429 VG_(deleteXA)(text); 430 } 431 432 433 /* Figure out if we want to perform a given action for this error, 434 possibly by asking the user. 435 */ 436 Bool VG_(is_action_requested) ( Char* action, Bool* clo ) 437 { 438 Char ch, ch2; 439 Int res; 440 441 /* First off, we shouldn't be asking the user anything if 442 we're in XML mode. */ 443 if (VG_(clo_xml)) 444 return False; /* That's a Nein, oder Nay as they say down here in B-W */ 445 446 if (*clo == False) 447 return False; 448 449 VG_(umsg)("\n"); 450 451 again: 452 VG_(printf)( 453 "==%d== " 454 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ", 455 VG_(getpid)(), action 456 ); 457 458 res = VG_(read)(VG_(clo_input_fd), &ch, 1); 459 if (res != 1) goto ioerror; 460 /* res == 1 */ 461 if (ch == '\n') return False; 462 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y' 463 && ch != 'C' && ch != 'c') goto again; 464 465 res = VG_(read)(VG_(clo_input_fd), &ch2, 1); 466 if (res != 1) goto ioerror; 467 if (ch2 != '\n') goto again; 468 469 /* No, don't want to do action. */ 470 if (ch == 'n' || ch == 'N') return False; 471 /* Yes, want to do action. */ 472 if (ch == 'y' || ch == 'Y') return True; 473 /* No, don't want to do action, and don't ask again either. */ 474 vg_assert(ch == 'c' || ch == 'C'); 475 476 ioerror: 477 *clo = False; 478 return False; 479 } 480 481 482 /* Do text-mode actions on error, that is, immediately after an error 483 is printed. These are: 484 * possibly, attach to a debugger 485 * possibly, generate a suppression. 486 Note this should not be called in XML mode! 487 */ 488 static 489 void do_actions_on_error(Error* err, Bool allow_db_attach) 490 { 491 Bool still_noisy = True; 492 493 /* Should be assured by caller */ 494 vg_assert( ! VG_(clo_xml) ); 495 496 /* Perhaps we want a debugger attach at this point? */ 497 if (allow_db_attach && 498 VG_(is_action_requested)( "Attach to debugger", & VG_(clo_db_attach) )) 499 { 500 if (0) VG_(printf)("starting debugger\n"); 501 VG_(start_debugger)( err->tid ); 502 } 503 /* Or maybe we want to generate the error's suppression? */ 504 if (VG_(clo_gen_suppressions) == 2 505 || (VG_(clo_gen_suppressions) == 1 506 && VG_(is_action_requested)( "Print suppression", &still_noisy )) 507 ) { 508 gen_suppression(err); 509 } 510 if (VG_(clo_gen_suppressions) == 1 && !still_noisy) 511 VG_(clo_gen_suppressions) = 0; 512 } 513 514 // See https://bugs.kde.org/show_bug.cgi?id=265803 and b/3423996 515 static Bool seen_pc_with_no_function_name_nor_object_file_name = False; 516 517 static Bool ErrHasNoFunctionNamesNorObjectFileNames(Error *err) { 518 // boil out if the stack trace has no function/object names. 519 StackTrace ips = VG_(get_ExeContext_StackTrace)(err->where); 520 UWord n_ips = VG_(get_ExeContext_n_ips)(err->where); 521 UWord i; 522 for (i = 0; i < n_ips; i++) { 523 Addr ip = ips[i]; 524 Char buffer[1024]; 525 if (VG_(get_fnname)(ip, buffer, sizeof(buffer))) { 526 return False; 527 } 528 if (VG_(get_objname)(ip, buffer, sizeof(buffer))) { 529 return False; 530 } 531 } 532 if (!seen_pc_with_no_function_name_nor_object_file_name) 533 VG_(umsg)("\n\n\nWARNING: Valgrind encountered a stack trace which has\n" 534 "no function names nor object file names.\n" 535 "Unless your program has a dynamically generated code (e.g. it is a JIT)\n" 536 "something is very much wrong with your binary's debug info.\n" 537 "See https://bugs.kde.org/show_bug.cgi?id=265803 and b/3423996\n\n\n" 538 ); 539 seen_pc_with_no_function_name_nor_object_file_name = True; 540 return True; 541 } 542 543 /* Prints an error. Not entirely simple because of the differences 544 between XML and text mode output. 545 546 In XML mode: 547 548 * calls the tool's pre-show method, so the tool can create any 549 preamble ahead of the message, if it wants. 550 551 * prints the opening tag, and the <unique> and <tid> fields 552 553 * prints the tool-specific parts of the message 554 555 * if suppression generation is required, a suppression 556 557 * the closing tag 558 559 In text mode: 560 561 * calls the tool's pre-show method, so the tool can create any 562 preamble ahead of the message, if it wants. 563 564 * prints the tool-specific parts of the message 565 566 * calls do_actions_on_error. This optionally does a debugger 567 attach (and detach), and optionally prints a suppression; both 568 of these may require user input. 569 */ 570 static void pp_Error ( Error* err, Bool allow_db_attach ) 571 { 572 /* If this fails, you probably specified your tool's method 573 dictionary incorrectly. */ 574 vg_assert(VG_(needs).tool_errors); 575 576 if (VG_(clo_xml)) { 577 578 /* Note, allow_db_attach is ignored in here. */ 579 580 /* Ensure that suppression generation is either completely 581 enabled or completely disabled; either way, we won't require 582 any user input. m_main.process_cmd_line_options should 583 ensure the asserted condition holds. */ 584 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */ 585 || VG_(clo_gen_suppressions) == 2 /* for all errors */ ); 586 587 /* Pre-show it to the tool */ 588 VG_TDICT_CALL( tool_before_pp_Error, err ); 589 590 /* standard preamble */ 591 VG_(printf_xml)("<error>\n"); 592 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique); 593 VG_(printf_xml)(" <tid>%d</tid>\n", err->tid); 594 595 /* actually print it */ 596 VG_TDICT_CALL( tool_pp_Error, err ); 597 598 if (VG_(clo_gen_suppressions) > 0) 599 gen_suppression(err); 600 601 /* postamble */ 602 VG_(printf_xml)("</error>\n"); 603 VG_(printf_xml)("\n"); 604 605 } else { 606 607 VG_TDICT_CALL( tool_before_pp_Error, err ); 608 609 if (VG_(tdict).tool_show_ThreadIDs_for_errors 610 && err->tid > 0 && err->tid != last_tid_printed) { 611 VG_(umsg)("Thread %d:\n", err->tid ); 612 last_tid_printed = err->tid; 613 } 614 615 VG_TDICT_CALL( tool_pp_Error, err ); 616 VG_(umsg)("\n"); 617 618 do_actions_on_error(err, allow_db_attach); 619 } 620 } 621 622 623 /* Construct an error */ 624 static 625 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a, 626 Char* s, void* extra, ExeContext* where ) 627 { 628 /* DO NOT MAKE unique_counter NON-STATIC */ 629 static UInt unique_counter = 0; 630 631 tl_assert(tid < VG_N_THREADS); 632 633 /* Core-only parts */ 634 err->unique = unique_counter++; 635 err->next = NULL; 636 err->supp = NULL; 637 err->count = 1; 638 err->tid = tid; 639 if (NULL == where) 640 err->where = VG_(record_ExeContext)( tid, 0 ); 641 else 642 err->where = where; 643 644 /* Tool-relevant parts */ 645 err->ekind = ekind; 646 err->addr = a; 647 err->extra = extra; 648 err->string = s; 649 650 /* sanity... */ 651 vg_assert( tid < VG_N_THREADS ); 652 } 653 654 655 656 static Int n_errs_shown = 0; 657 658 /* Top-level entry point to the error management subsystem. 659 All detected errors are notified here; this routine decides if/when the 660 user should see the error. */ 661 void VG_(maybe_record_error) ( ThreadId tid, 662 ErrorKind ekind, Addr a, Char* s, void* extra ) 663 { 664 Error err; 665 Error* p; 666 Error* p_prev; 667 UInt extra_size; 668 VgRes exe_res = Vg_MedRes; 669 static Bool stopping_message = False; 670 static Bool slowdown_message = False; 671 672 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have 673 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors 674 have been found, just refuse to collect any more. This stops 675 the burden of the error-management system becoming excessive in 676 extremely buggy programs, although it does make it pretty 677 pointless to continue the Valgrind run after this point. */ 678 if (VG_(clo_error_limit) 679 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN 680 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND) 681 && !VG_(clo_xml)) { 682 if (!stopping_message) { 683 VG_(umsg)("\n"); 684 685 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) { 686 VG_(umsg)( 687 "More than %d different errors detected. " 688 "I'm not reporting any more.\n", 689 M_COLLECT_NO_ERRORS_AFTER_SHOWN ); 690 } else { 691 VG_(umsg)( 692 "More than %d total errors detected. " 693 "I'm not reporting any more.\n", 694 M_COLLECT_NO_ERRORS_AFTER_FOUND ); 695 } 696 697 VG_(umsg)("Final error counts will be inaccurate. " 698 "Go fix your program!\n"); 699 VG_(umsg)("Rerun with --error-limit=no to disable " 700 "this cutoff. Note\n"); 701 VG_(umsg)("that errors may occur in your program without " 702 "prior warning from\n"); 703 VG_(umsg)("Valgrind, because errors are no longer " 704 "being displayed.\n"); 705 VG_(umsg)("\n"); 706 stopping_message = True; 707 } 708 return; 709 } 710 711 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have 712 been found, be much more conservative about collecting new 713 ones. */ 714 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER 715 && !VG_(clo_xml)) { 716 exe_res = Vg_LowRes; 717 if (!slowdown_message) { 718 VG_(umsg)("\n"); 719 VG_(umsg)("More than %d errors detected. Subsequent errors\n", 720 M_COLLECT_ERRORS_SLOWLY_AFTER); 721 VG_(umsg)("will still be recorded, but in less " 722 "detail than before.\n"); 723 slowdown_message = True; 724 } 725 } else if (seen_pc_with_no_function_name_nor_object_file_name) { 726 // we are probably inside some unknown code -- don't spend too much time 727 // matching the error reports. 728 exe_res = Vg_LowRes; 729 } 730 731 /* Build ourselves the error */ 732 construct_error ( &err, tid, ekind, a, s, extra, NULL ); 733 734 /* First, see if we've got an error record matching this one. */ 735 em_errlist_searches++; 736 p = errors; 737 p_prev = NULL; 738 while (p != NULL) { 739 em_errlist_cmps++; 740 if (eq_Error(exe_res, p, &err)) { 741 /* Found it. */ 742 p->count++; 743 if (p->supp != NULL) { 744 /* Deal correctly with suppressed errors. */ 745 p->supp->count++; 746 n_errs_suppressed++; 747 } else { 748 if (!seen_pc_with_no_function_name_nor_object_file_name) 749 n_errs_found++; 750 } 751 752 /* Move p to the front of the list so that future searches 753 for it are faster. */ 754 if (p_prev != NULL) { 755 vg_assert(p_prev->next == p); 756 p_prev->next = p->next; 757 p->next = errors; 758 errors = p; 759 } 760 761 return; 762 } 763 p_prev = p; 764 p = p->next; 765 } 766 767 /* Didn't see it. Copy and add. */ 768 769 /* OK, we're really going to collect it. The context is on the stack and 770 will disappear shortly, so we must copy it. First do the main 771 (non-'extra') part. 772 773 Then VG_(tdict).tool_update_extra can update the 'extra' part. This 774 is for when there are more details to fill in which take time to work 775 out but don't affect our earlier decision to include the error -- by 776 postponing those details until now, we avoid the extra work in the 777 case where we ignore the error. Ugly. 778 779 Then, if there is an 'extra' part, copy it too, using the size that 780 VG_(tdict).tool_update_extra returned. Also allow for people using 781 the void* extra field for a scalar value like an integer. 782 */ 783 784 /* copy main part */ 785 p = VG_(arena_malloc)(VG_AR_ERRORS, "errormgr.mre.1", sizeof(Error)); 786 *p = err; 787 788 /* update 'extra' */ 789 switch (ekind) { 790 //(example code, see comment on CoreSuppKind above) 791 //case ThreadErr: 792 // vg_assert(VG_(needs).core_errors); 793 // extra_size = <something> 794 // break; 795 default: 796 vg_assert(VG_(needs).tool_errors); 797 extra_size = VG_TDICT_CALL(tool_update_extra, p); 798 break; 799 } 800 801 /* copy block pointed to by 'extra', if there is one */ 802 if (NULL != p->extra && 0 != extra_size) { 803 void* new_extra = VG_(malloc)("errormgr.mre.2", extra_size); 804 VG_(memcpy)(new_extra, p->extra, extra_size); 805 p->extra = new_extra; 806 } 807 808 p->next = errors; 809 p->supp = is_suppressible_error(&err); 810 errors = p; 811 812 if (ErrHasNoFunctionNamesNorObjectFileNames(p)) 813 return; 814 815 if (p->supp == NULL) { 816 n_err_contexts++; 817 n_errs_found++; 818 /* Actually show the error; more complex than you might think. */ 819 pp_Error( p, /*allow_db_attach*/True ); 820 /* update stats */ 821 n_errs_shown++; 822 } else { 823 n_supp_contexts++; 824 n_errs_suppressed++; 825 p->supp->count++; 826 } 827 } 828 829 /* Second top-level entry point to the error management subsystem, for 830 errors that the tool wants to report immediately, eg. because they're 831 guaranteed to only happen once. This avoids all the recording and 832 comparing stuff. But they can be suppressed; returns True if it is 833 suppressed. Bool 'print_error' dictates whether to print the error. 834 Bool 'count_error' dictates whether to count the error in n_errs_found. 835 */ 836 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s, 837 void* extra, ExeContext* where, Bool print_error, 838 Bool allow_db_attach, Bool count_error ) 839 { 840 Error err; 841 Supp *su; 842 843 /* Build ourselves the error */ 844 construct_error ( &err, tid, ekind, a, s, extra, where ); 845 846 /* Unless it's suppressed, we're going to show it. Don't need to make 847 a copy, because it's only temporary anyway. 848 849 Then update the 'extra' part with VG_(tdict).tool_update_extra), 850 because that can have an affect on whether it's suppressed. Ignore 851 the size return value of VG_(tdict).tool_update_extra, because we're 852 not copying 'extra'. */ 853 (void)VG_TDICT_CALL(tool_update_extra, &err); 854 855 su = is_suppressible_error(&err); 856 if (NULL == su) { 857 if (count_error) { 858 n_errs_found++; 859 n_err_contexts++; 860 } 861 862 if (print_error) { 863 /* Actually show the error; more complex than you might think. */ 864 pp_Error(&err, allow_db_attach); 865 /* update stats */ 866 n_errs_shown++; 867 } 868 return False; 869 870 } else { 871 if (count_error) { 872 n_errs_suppressed++; 873 n_supp_contexts++; 874 } 875 su->count++; 876 return True; 877 } 878 } 879 880 881 /*------------------------------------------------------------*/ 882 /*--- Exported fns ---*/ 883 /*------------------------------------------------------------*/ 884 885 /* Show the used suppressions. Returns False if no suppression 886 got used. */ 887 static Bool show_used_suppressions ( void ) 888 { 889 Supp *su; 890 Bool any_supp; 891 892 if (VG_(clo_xml)) 893 VG_(printf_xml)("<suppcounts>\n"); 894 895 any_supp = False; 896 for (su = suppressions; su != NULL; su = su->next) { 897 if (su->count <= 0) 898 continue; 899 if (VG_(clo_xml)) { 900 VG_(printf_xml_no_f_c)( " <pair>\n" 901 " <count>%d</count>\n" 902 " <name>%t</name>\n" 903 " </pair>\n", 904 su->count, su->sname ); 905 } else { 906 // blank line before the first shown suppression, if any 907 if (!any_supp) 908 VG_(dmsg)("\n"); 909 VG_(dmsg)("used_suppression: %6d %s\n", su->count, su->sname); 910 } 911 any_supp = True; 912 } 913 914 if (VG_(clo_xml)) 915 VG_(printf_xml)("</suppcounts>\n"); 916 917 return any_supp; 918 } 919 920 921 /* Show all the errors that occurred, and possibly also the 922 suppressions used. */ 923 void VG_(show_all_errors) ( void ) 924 { 925 Int i, n_min; 926 Error *p, *p_min; 927 Bool any_supp; 928 929 if (VG_(clo_verbosity) == 0) 930 return; 931 932 /* If we're printing XML, just show the suppressions and stop. */ 933 if (VG_(clo_xml)) { 934 (void)show_used_suppressions(); 935 return; 936 } 937 938 /* We only get here if not printing XML. */ 939 VG_(umsg)("ERROR SUMMARY: " 940 "%d errors from %d contexts (suppressed: %d from %d)\n", 941 n_errs_found, n_err_contexts, 942 n_errs_suppressed, n_supp_contexts ); 943 944 if (VG_(clo_verbosity) <= 1) 945 return; 946 947 // We do the following only at -v or above, and only in non-XML 948 // mode 949 950 /* Print the contexts in order of increasing error count. */ 951 for (i = 0; i < n_err_contexts; i++) { 952 n_min = (1 << 30) - 1; 953 p_min = NULL; 954 for (p = errors; p != NULL; p = p->next) { 955 if (p->supp != NULL) continue; 956 if (p->count < n_min) { 957 n_min = p->count; 958 p_min = p; 959 } 960 } 961 // XXX: this isn't right. See bug 203651. 962 if (p_min == NULL) continue; //VG_(tool_panic)("show_all_errors()"); 963 964 VG_(umsg)("\n"); 965 VG_(umsg)("%d errors in context %d of %d:\n", 966 p_min->count, i+1, n_err_contexts); 967 pp_Error( p_min, False/*allow_db_attach*/ ); 968 969 // We're not printing XML -- we'd have exited above if so. 970 vg_assert(! VG_(clo_xml)); 971 972 if ((i+1 == VG_(clo_dump_error))) { 973 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where); 974 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/, 975 ips[0], /*debugging*/True, 0xFE/*verbosity*/, 976 /*bbs_done*/0, 977 /*allow redir?*/True); 978 } 979 980 p_min->count = 1 << 30; 981 } 982 983 any_supp = show_used_suppressions(); 984 985 if (any_supp) 986 VG_(umsg)("\n"); 987 // reprint this, so users don't have to scroll way up to find 988 // the first printing 989 VG_(umsg)("ERROR SUMMARY: " 990 "%d errors from %d contexts (suppressed: %d from %d)\n", 991 n_errs_found, n_err_contexts, n_errs_suppressed, 992 n_supp_contexts ); 993 } 994 995 996 /* Show occurrence counts of all errors, in XML form. */ 997 void VG_(show_error_counts_as_XML) ( void ) 998 { 999 Error* err; 1000 VG_(printf_xml)("<errorcounts>\n"); 1001 for (err = errors; err != NULL; err = err->next) { 1002 if (err->supp != NULL) 1003 continue; 1004 if (err->count <= 0) 1005 continue; 1006 VG_(printf_xml)(" <pair>\n"); 1007 VG_(printf_xml)(" <count>%d</count>\n", err->count); 1008 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique); 1009 VG_(printf_xml)(" </pair>\n"); 1010 } 1011 VG_(printf_xml)("</errorcounts>\n"); 1012 VG_(printf_xml)("\n"); 1013 } 1014 1015 1016 /*------------------------------------------------------------*/ 1017 /*--- Suppression parsing ---*/ 1018 /*------------------------------------------------------------*/ 1019 1020 /* Get the next char from fd into *out_buf. Returns 1 if success, 1021 0 if eof or < 0 if error. */ 1022 1023 static Int get_char ( Int fd, Char* out_buf ) 1024 { 1025 Int r; 1026 static Char buf[256]; 1027 static Int buf_size = 0; 1028 static Int buf_used = 0; 1029 vg_assert(buf_size >= 0 && buf_size <= 256); 1030 vg_assert(buf_used >= 0 && buf_used <= buf_size); 1031 if (buf_used == buf_size) { 1032 r = VG_(read)(fd, buf, 256); 1033 if (r < 0) return r; /* read failed */ 1034 vg_assert(r >= 0 && r <= 256); 1035 buf_size = r; 1036 buf_used = 0; 1037 } 1038 if (buf_size == 0) 1039 return 0; /* eof */ 1040 vg_assert(buf_size >= 0 && buf_size <= 256); 1041 vg_assert(buf_used >= 0 && buf_used < buf_size); 1042 *out_buf = buf[buf_used]; 1043 buf_used++; 1044 return 1; 1045 } 1046 1047 Bool VG_(get_line) ( Int fd, Char** bufpp, SizeT* nBufp, Int* lineno ) 1048 { 1049 Char* buf = *bufpp; 1050 SizeT nBuf = *nBufp; 1051 Char ch; 1052 Int n, i; 1053 while (True) { 1054 /* First, read until a non-blank char appears. */ 1055 while (True) { 1056 n = get_char(fd, &ch); 1057 if (n == 1 && !VG_(isspace)(ch)) break; 1058 if (n == 1 && ch == '\n' && lineno) 1059 (*lineno)++; 1060 if (n <= 0) return True; 1061 } 1062 1063 /* Now, read the line into buf. */ 1064 i = 0; 1065 buf[i++] = ch; buf[i] = 0; 1066 while (True) { 1067 n = get_char(fd, &ch); 1068 if (n <= 0) return False; /* the next call will return True */ 1069 if (ch == '\n' && lineno) 1070 (*lineno)++; 1071 if (ch == '\n') break; 1072 if (i > 0 && i == nBuf-1) { 1073 *nBufp = nBuf = nBuf * 2; 1074 #define RIDICULOUS 100000 1075 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really. 1076 "VG_(get_line): line longer than %d chars, aborting\n", 1077 RIDICULOUS); 1078 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf); 1079 } 1080 buf[i++] = ch; buf[i] = 0; 1081 } 1082 while (i > 1 && VG_(isspace)(buf[i-1])) { 1083 i--; buf[i] = 0; 1084 }; 1085 1086 /* VG_(printf)("The line is '%s'\n", buf); */ 1087 /* Ok, we have a line. If a non-comment line, return. 1088 If a comment line, start all over again. */ 1089 if (buf[0] != '#') return False; 1090 } 1091 } 1092 1093 1094 /* *p_caller contains the raw name of a caller, supposedly either 1095 fun:some_function_name or 1096 obj:some_object_name. 1097 Set *p_ty accordingly and advance *p_caller over the descriptor 1098 (fun: or obj:) part. 1099 Returns False if failed. 1100 */ 1101 static Bool setLocationTy ( SuppLoc* p ) 1102 { 1103 if (VG_(strncmp)(p->name, "fun:", 4) == 0) { 1104 p->name += 4; 1105 p->ty = FunName; 1106 return True; 1107 } 1108 if (VG_(strncmp)(p->name, "obj:", 4) == 0) { 1109 p->name += 4; 1110 p->ty = ObjName; 1111 return True; 1112 } 1113 if (VG_(strcmp)(p->name, "...") == 0) { 1114 p->name = NULL; 1115 p->ty = DotDotDot; 1116 return True; 1117 } 1118 VG_(printf)("location should be \"...\", or should start " 1119 "with \"fun:\" or \"obj:\"\n"); 1120 return False; 1121 } 1122 1123 1124 /* Look for "tool" in a string like "tool1,tool2,tool3" */ 1125 static Bool tool_name_present(Char *name, Char *names) 1126 { 1127 Bool found; 1128 Char *s = NULL; /* Shut gcc up */ 1129 Int len = VG_(strlen)(name); 1130 1131 found = (NULL != (s = VG_(strstr)(names, name)) && 1132 (s == names || *(s-1) == ',') && 1133 (*(s+len) == ',' || *(s+len) == '\0') 1134 ); 1135 1136 return found; 1137 } 1138 1139 /* Read suppressions from the file specified in VG_(clo_suppressions) 1140 and place them in the suppressions list. If there's any difficulty 1141 doing this, just give up -- there's no point in trying to recover. 1142 */ 1143 static void load_one_suppressions_file ( Char* filename ) 1144 { 1145 SysRes sres; 1146 Int fd, i, j, lineno = 0; 1147 Bool eof; 1148 SizeT nBuf = 200; 1149 Char* buf = VG_(malloc)("errormgr.losf.1", nBuf); 1150 Char* tool_names; 1151 Char* supp_name; 1152 Char* err_str = NULL; 1153 SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS]; 1154 1155 // Check it's not a directory. 1156 if (VG_(is_dir)( filename )) { 1157 if (VG_(clo_xml)) 1158 VG_(printf_xml)("</valgrindoutput>\n"); 1159 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename ); 1160 VG_(exit)(1); 1161 } 1162 1163 // Open the suppression file. 1164 sres = VG_(open)( filename, VKI_O_RDONLY, 0 ); 1165 if (sr_isError(sres)) { 1166 if (VG_(clo_xml)) 1167 VG_(printf_xml)("</valgrindoutput>\n"); 1168 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename ); 1169 VG_(exit)(1); 1170 } 1171 fd = sr_Res(sres); 1172 1173 # define BOMB(S) { err_str = S; goto syntax_error; } 1174 1175 while (True) { 1176 /* Assign and initialise the two suppression halves (core and tool) */ 1177 Supp* supp; 1178 supp = VG_(arena_malloc)(VG_AR_CORE, "errormgr.losf.1", 1179 sizeof(Supp)); 1180 supp->count = 0; 1181 1182 // Initialise temporary reading-in buffer. 1183 for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) { 1184 tmp_callers[i].ty = NoName; 1185 tmp_callers[i].name = NULL; 1186 } 1187 1188 supp->string = supp->extra = NULL; 1189 1190 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno ); 1191 if (eof) break; 1192 1193 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file"); 1194 1195 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno ); 1196 1197 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'"); 1198 1199 supp->sname = VG_(arena_strdup)(VG_AR_CORE, "errormgr.losf.2", buf); 1200 1201 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno ); 1202 1203 if (eof) BOMB("unexpected end-of-file"); 1204 1205 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */ 1206 i = 0; 1207 while (True) { 1208 if (buf[i] == ':') break; 1209 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line"); 1210 i++; 1211 } 1212 buf[i] = '\0'; /* Replace ':', splitting into two strings */ 1213 1214 tool_names = & buf[0]; 1215 supp_name = & buf[i+1]; 1216 1217 if (VG_(needs).core_errors && tool_name_present("core", tool_names)) 1218 { 1219 // A core suppression 1220 //(example code, see comment on CoreSuppKind above) 1221 //if (VG_STREQ(supp_name, "Thread")) 1222 // supp->skind = ThreadSupp; 1223 //else 1224 BOMB("unknown core suppression type"); 1225 } 1226 else if (VG_(needs).tool_errors && 1227 tool_name_present(VG_(details).name, tool_names)) 1228 { 1229 // A tool suppression 1230 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) { 1231 /* Do nothing, function fills in supp->skind */ 1232 } else { 1233 BOMB("unknown tool suppression type"); 1234 } 1235 } 1236 else { 1237 // Ignore rest of suppression 1238 while (True) { 1239 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno ); 1240 if (eof) BOMB("unexpected end-of-file"); 1241 if (VG_STREQ(buf, "}")) 1242 break; 1243 } 1244 continue; 1245 } 1246 1247 if (VG_(needs).tool_errors && 1248 !VG_TDICT_CALL(tool_read_extra_suppression_info, 1249 fd, &buf, &nBuf, supp)) 1250 { 1251 BOMB("bad or missing extra suppression info"); 1252 } 1253 1254 /* the main frame-descriptor reading loop */ 1255 i = 0; 1256 while (True) { 1257 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno ); 1258 if (eof) 1259 BOMB("unexpected end-of-file"); 1260 if (VG_STREQ(buf, "}")) { 1261 if (i > 0) { 1262 break; 1263 } else { 1264 BOMB("missing stack trace"); 1265 } 1266 } 1267 if (i == VG_MAX_SUPP_CALLERS) 1268 BOMB("too many callers in stack trace"); 1269 if (i > 0 && i >= VG_(clo_backtrace_size)) 1270 break; 1271 tmp_callers[i].name = VG_(arena_strdup)(VG_AR_CORE, 1272 "errormgr.losf.3", buf); 1273 if (!setLocationTy(&(tmp_callers[i]))) 1274 BOMB("location should be \"...\", or should start " 1275 "with \"fun:\" or \"obj:\""); 1276 i++; 1277 } 1278 1279 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra 1280 // lines and grab the '}'. 1281 if (!VG_STREQ(buf, "}")) { 1282 do { 1283 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno ); 1284 } while (!eof && !VG_STREQ(buf, "}")); 1285 } 1286 1287 // Reject entries which are entirely composed of frame 1288 // level wildcards. 1289 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop 1290 for (j = 0; j < i; j++) { 1291 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName) 1292 break; 1293 vg_assert(tmp_callers[j].ty == DotDotDot); 1294 } 1295 vg_assert(j >= 0 && j <= i); 1296 if (j == i) { 1297 // we didn't find any non-"..." entries 1298 BOMB("suppression must contain at least one location " 1299 "line which is not \"...\""); 1300 } 1301 1302 // Copy tmp_callers[] into supp->callers[] 1303 supp->n_callers = i; 1304 supp->callers = VG_(arena_malloc)(VG_AR_CORE, "errormgr.losf.4", 1305 i*sizeof(SuppLoc)); 1306 for (i = 0; i < supp->n_callers; i++) { 1307 supp->callers[i] = tmp_callers[i]; 1308 } 1309 1310 supp->next = suppressions; 1311 suppressions = supp; 1312 } 1313 VG_(free)(buf); 1314 VG_(close)(fd); 1315 return; 1316 1317 syntax_error: 1318 if (VG_(clo_xml)) 1319 VG_(printf_xml)("</valgrindoutput>\n"); 1320 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n", 1321 filename, lineno ); 1322 VG_(umsg)(" %s\n", err_str ); 1323 1324 VG_(close)(fd); 1325 VG_(umsg)("exiting now.\n"); 1326 VG_(exit)(1); 1327 1328 # undef BOMB 1329 } 1330 1331 1332 void VG_(load_suppressions) ( void ) 1333 { 1334 Int i; 1335 suppressions = NULL; 1336 for (i = 0; i < VG_(clo_n_suppressions); i++) { 1337 if (VG_(clo_verbosity) > 1) { 1338 VG_(dmsg)("Reading suppressions file: %s\n", 1339 VG_(clo_suppressions)[i] ); 1340 } 1341 load_one_suppressions_file( VG_(clo_suppressions)[i] ); 1342 } 1343 } 1344 1345 1346 /*------------------------------------------------------------*/ 1347 /*--- Matching errors to suppressions ---*/ 1348 /*------------------------------------------------------------*/ 1349 1350 /* Parameterising functions for the use of VG_(generic_match) in 1351 suppression-vs-error matching. The suppression frames (SuppLoc) 1352 play the role of 'pattern'-element, and the error frames (IPs, 1353 hence simply Addrs) play the role of 'input'. In short then, we're 1354 matching a sequence of Addrs against a pattern composed of a 1355 sequence of SuppLocs. 1356 */ 1357 static Bool supploc_IsStar ( void* supplocV ) 1358 { 1359 SuppLoc* supploc = (SuppLoc*)supplocV; 1360 return supploc->ty == DotDotDot; 1361 } 1362 1363 static Bool supploc_IsQuery ( void* supplocV ) 1364 { 1365 return False; /* there's no '?' equivalent in the supp syntax */ 1366 } 1367 1368 static Bool supp_pattEQinp ( void* supplocV, void* addrV ) 1369 { 1370 SuppLoc* supploc = (SuppLoc*)supplocV; /* PATTERN */ 1371 Addr ip = *(Addr*)addrV; /* INPUT */ 1372 1373 Char caller_name[ERRTXT_LEN]; 1374 caller_name[0] = 0; 1375 1376 /* So, does this IP address match this suppression-line? */ 1377 switch (supploc->ty) { 1378 case DotDotDot: 1379 /* supp_pattEQinp is a callback from VG_(generic_match). As 1380 per the spec thereof (see include/pub_tool_seqmatch.h), we 1381 should never get called with a pattern value for which the 1382 _IsStar or _IsQuery function would return True. Hence 1383 this can't happen. */ 1384 vg_assert(0); 1385 case ObjName: 1386 /* Get the object name into 'caller_name', or "???" 1387 if unknown. */ 1388 if (!VG_(get_objname)(ip, caller_name, ERRTXT_LEN)) 1389 VG_(strcpy)(caller_name, "???"); 1390 break; 1391 case FunName: 1392 /* Get the function name into 'caller_name', or "???" 1393 if unknown. */ 1394 // Nb: C++-mangled names are used in suppressions. Do, though, 1395 // Z-demangle them, since otherwise it's possible to wind 1396 // up comparing "malloc" in the suppression against 1397 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the 1398 // two of them need to be made to match. 1399 if (!VG_(get_fnname_no_cxx_demangle)(ip, caller_name, ERRTXT_LEN)) 1400 VG_(strcpy)(caller_name, "???"); 1401 break; 1402 default: 1403 vg_assert(0); 1404 } 1405 1406 /* So now we have the function or object name in caller_name, and 1407 the pattern (at the character level) to match against is in 1408 supploc->name. Hence (and leading to a re-entrant call of 1409 VG_(generic_match)): */ 1410 return VG_(string_match)(supploc->name, caller_name); 1411 } 1412 1413 ///////////////////////////////////////////////////// 1414 1415 static Bool supp_matches_callers(Error* err, Supp* su) 1416 { 1417 /* Unwrap the args and set up the correct parameterisation of 1418 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and 1419 supp_pattEQinp. */ 1420 /* note, StackTrace === Addr* */ 1421 StackTrace ips = VG_(get_ExeContext_StackTrace)(err->where); 1422 UWord n_ips = VG_(get_ExeContext_n_ips)(err->where); 1423 SuppLoc* supps = su->callers; 1424 UWord n_supps = su->n_callers; 1425 UWord szbPatt = sizeof(SuppLoc); 1426 UWord szbInput = sizeof(Addr); 1427 Bool matchAll = False; /* we just want to match a prefix */ 1428 return 1429 VG_(generic_match)( 1430 matchAll, 1431 /*PATT*/supps, szbPatt, n_supps, 0/*initial Ix*/, 1432 /*INPUT*/ips, szbInput, n_ips, 0/*initial Ix*/, 1433 supploc_IsStar, supploc_IsQuery, supp_pattEQinp 1434 ); 1435 } 1436 1437 ///////////////////////////////////////////////////// 1438 1439 static 1440 Bool supp_matches_error(Supp* su, Error* err) 1441 { 1442 switch (su->skind) { 1443 //(example code, see comment on CoreSuppKind above) 1444 //case ThreadSupp: 1445 // return (err->ekind == ThreadErr); 1446 default: 1447 if (VG_(needs).tool_errors) { 1448 return VG_TDICT_CALL(tool_error_matches_suppression, err, su); 1449 } else { 1450 VG_(printf)( 1451 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n" 1452 "probably needs to be set.\n", 1453 err->ekind); 1454 VG_(tool_panic)("unhandled suppression type"); 1455 } 1456 } 1457 } 1458 1459 ///////////////////////////////////////////////////// 1460 1461 /* Does an error context match a suppression? ie is this a suppressible 1462 error? If so, return a pointer to the Supp record, otherwise NULL. 1463 Tries to minimise the number of symbol searches since they are expensive. 1464 */ 1465 static Supp* is_suppressible_error ( Error* err ) 1466 { 1467 Supp* su; 1468 Supp* su_prev; 1469 1470 /* stats gathering */ 1471 em_supplist_searches++; 1472 1473 /* See if the error context matches any suppression. */ 1474 su_prev = NULL; 1475 for (su = suppressions; su != NULL; su = su->next) { 1476 em_supplist_cmps++; 1477 if (supp_matches_error(su, err) && supp_matches_callers(err, su)) { 1478 /* got a match. Move this entry to the head of the list 1479 in the hope of making future searches cheaper. */ 1480 if (su_prev) { 1481 vg_assert(su_prev->next == su); 1482 su_prev->next = su->next; 1483 su->next = suppressions; 1484 suppressions = su; 1485 } 1486 return su; 1487 } 1488 su_prev = su; 1489 } 1490 return NULL; /* no matches */ 1491 } 1492 1493 /* Show accumulated error-list and suppression-list search stats. 1494 */ 1495 void VG_(print_errormgr_stats) ( void ) 1496 { 1497 VG_(dmsg)( 1498 " errormgr: %'lu supplist searches, %'lu comparisons during search\n", 1499 em_supplist_searches, em_supplist_cmps 1500 ); 1501 VG_(dmsg)( 1502 " errormgr: %'lu errlist searches, %'lu comparisons during search\n", 1503 em_errlist_searches, em_errlist_cmps 1504 ); 1505 } 1506 1507 /*--------------------------------------------------------------------*/ 1508 /*--- end ---*/ 1509 /*--------------------------------------------------------------------*/ 1510