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-2017 Julian Seward
11 jseward@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_debuginfo.h"
35 #include "pub_core_debuglog.h"
36 #include "pub_core_errormgr.h"
37 #include "pub_core_execontext.h"
38 #include "pub_core_gdbserver.h"
39 #include "pub_core_libcbase.h"
40 #include "pub_core_libcassert.h"
41 #include "pub_core_libcfile.h"
42 #include "pub_core_libcprint.h"
43 #include "pub_core_libcproc.h" // For VG_(getpid)()
44 #include "pub_core_seqmatch.h"
45 #include "pub_core_mallocfree.h"
46 #include "pub_core_options.h"
47 #include "pub_core_stacktrace.h"
48 #include "pub_core_tooliface.h"
49 #include "pub_core_translate.h" // for VG_(translate)()
50 #include "pub_core_xarray.h" // VG_(xaprintf) et al
51
52 #define DEBUG_ERRORMGR 0 // set to 1 for heavyweight tracing
53
54 /*------------------------------------------------------------*/
55 /*--- Globals ---*/
56 /*------------------------------------------------------------*/
57
58 /* After this many different unsuppressed errors have been observed,
59 be more conservative about collecting new ones. */
60 #define M_COLLECT_ERRORS_SLOWLY_AFTER 100
61
62 /* After this many different unsuppressed errors have been observed,
63 stop collecting errors at all, and tell the user their program is
64 evidently a steaming pile of camel dung. */
65 #define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000
66
67 /* After this many total errors have been observed, stop collecting
68 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
69 #define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000
70
71 /* The list of error contexts found, both suppressed and unsuppressed.
72 Initially empty, and grows as errors are detected. */
73 static Error* errors = NULL;
74
75 /* The list of suppression directives, as read from the specified
76 suppressions file. Note that the list gets rearranged as a result
77 of the searches done by is_suppressible_error(). */
78 static Supp* suppressions = NULL;
79
80 /* Running count of unsuppressed errors detected. */
81 static UInt n_errs_found = 0;
82
83 /* Running count of suppressed errors detected. */
84 static UInt n_errs_suppressed = 0;
85
86 /* Running count of errors shown. */
87 static UInt n_errs_shown = 0;
88
89 /* Running count of unsuppressed error contexts. */
90 static UInt n_err_contexts = 0;
91
92 /* Running count of suppressed error contexts. */
93 static UInt n_supp_contexts = 0;
94
95
96 /* forwards ... */
97 static Supp* is_suppressible_error ( const Error* err );
98
99 static ThreadId last_tid_printed = 1;
100
101 /* Stats: number of searches of the error list initiated. */
102 static UWord em_errlist_searches = 0;
103
104 /* Stats: number of comparisons done during error list
105 searching. */
106 static UWord em_errlist_cmps = 0;
107
108 /* Stats: number of searches of the suppression list initiated. */
109 static UWord em_supplist_searches = 0;
110
111 /* Stats: number of comparisons done during suppression list
112 searching. */
113 static UWord em_supplist_cmps = 0;
114
115 /*------------------------------------------------------------*/
116 /*--- Error type ---*/
117 /*------------------------------------------------------------*/
118
119 /* Errors. Extensible (via the 'extra' field). Tools can use a normal
120 enum (with element values in the normal range (0..)) for 'ekind'.
121 Functions for getting/setting the tool-relevant fields are in
122 include/pub_tool_errormgr.h.
123
124 When errors are found and recorded with VG_(maybe_record_error)(), all
125 the tool must do is pass in the four parameters; core will
126 allocate/initialise the error record.
127 */
128 struct _Error {
129 struct _Error* next;
130 // Unique tag. This gives the error a unique identity (handle) by
131 // which it can be referred to afterwords. Currently only used for
132 // XML printing.
133 UInt unique;
134 // NULL if unsuppressed; or ptr to suppression record.
135 Supp* supp;
136 Int count;
137
138 // The tool-specific part
139 ThreadId tid; // Initialised by core
140 ExeContext* where; // Initialised by core
141 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
142 Addr addr; // Used frequently
143 const HChar* string; // Used frequently
144 void* extra; // For any tool-specific extras
145 };
146
147
VG_(get_error_where)148 ExeContext* VG_(get_error_where) ( const Error* err )
149 {
150 return err->where;
151 }
152
VG_(get_error_kind)153 ErrorKind VG_(get_error_kind) ( const Error* err )
154 {
155 return err->ekind;
156 }
157
VG_(get_error_address)158 Addr VG_(get_error_address) ( const Error* err )
159 {
160 return err->addr;
161 }
162
VG_(get_error_string)163 const HChar* VG_(get_error_string) ( const Error* err )
164 {
165 return err->string;
166 }
167
VG_(get_error_extra)168 void* VG_(get_error_extra) ( const Error* err )
169 {
170 return err->extra;
171 }
172
VG_(get_n_errs_found)173 UInt VG_(get_n_errs_found)( void )
174 {
175 return n_errs_found;
176 }
177
VG_(get_n_errs_shown)178 UInt VG_(get_n_errs_shown)( void )
179 {
180 return n_errs_shown;
181 }
182
183 /*------------------------------------------------------------*/
184 /*--- Suppression type ---*/
185 /*------------------------------------------------------------*/
186
187 /* Note: it is imperative this doesn't overlap with (0..) at all, as tools
188 * effectively extend it by defining their own enums in the (0..) range. */
189 typedef
190 enum {
191 // Nb: thread errors are a relic of the time when Valgrind's core
192 // could detect them. This example is left commented-out as an
193 // example should new core errors ever be added.
194 ThreadSupp = -1, /* Matches ThreadErr */
195 }
196 CoreSuppKind;
197
198 /* Max number of callers for context in a suppression is
199 VG_DEEPEST_BACKTRACE. */
200
201 /* For each caller specified for a suppression, record the nature of
202 the caller name. Not of interest to tools. */
203 typedef
204 enum {
205 NoName, /* Error case */
206 ObjName, /* Name is of an shared object file. */
207 FunName, /* Name is of a function. */
208 DotDotDot /* Frame-level wildcard */
209 }
210 SuppLocTy;
211
212 typedef
213 struct {
214 SuppLocTy ty;
215 Bool name_is_simple_str; /* True if name is a string without
216 '?' and '*' wildcard characters. */
217 HChar* name; /* NULL for NoName and DotDotDot */
218 }
219 SuppLoc;
220
221 /* Suppressions. Tools can get/set tool-relevant parts with functions
222 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field.
223 Tools can use a normal enum (with element values in the normal range
224 (0..)) for 'skind'. */
225 struct _Supp {
226 struct _Supp* next;
227 Int count; // The number of times this error has been suppressed.
228 HChar* sname; // The name by which the suppression is referred to.
229
230 // Index in VG_(clo_suppressions) giving filename from which suppression
231 // was read, and the lineno in this file where sname was read.
232 Int clo_suppressions_i;
233 Int sname_lineno;
234
235 // Length of 'callers'
236 Int n_callers;
237 // Array of callers, for matching stack traces. First one (name of fn
238 // where err occurs) is mandatory; rest are optional.
239 SuppLoc* callers;
240
241 /* The tool-specific part */
242 SuppKind skind; // What kind of suppression. Must use the range (0..).
243 HChar* string; // String -- use is optional. NULL by default.
244 void* extra; // Anything else -- use is optional. NULL by default.
245 };
246
VG_(get_supp_kind)247 SuppKind VG_(get_supp_kind) ( const Supp* su )
248 {
249 return su->skind;
250 }
251
VG_(get_supp_string)252 HChar* VG_(get_supp_string) ( const Supp* su )
253 {
254 return su->string;
255 }
256
VG_(get_supp_extra)257 void* VG_(get_supp_extra) ( const Supp* su )
258 {
259 return su->extra;
260 }
261
262
VG_(set_supp_kind)263 void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
264 {
265 su->skind = skind;
266 }
267
VG_(set_supp_string)268 void VG_(set_supp_string) ( Supp* su, HChar* string )
269 {
270 su->string = string;
271 }
272
VG_(set_supp_extra)273 void VG_(set_supp_extra) ( Supp* su, void* extra )
274 {
275 su->extra = extra;
276 }
277
278
279 /*------------------------------------------------------------*/
280 /*--- Helper fns ---*/
281 /*------------------------------------------------------------*/
282
283 // Only show core errors if the tool wants to, we're not running with -q,
284 // and were not outputting XML.
VG_(showing_core_errors)285 Bool VG_(showing_core_errors)(void)
286 {
287 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
288 }
289
290 /* Compare errors, to detect duplicates.
291 */
eq_Error(VgRes res,const Error * e1,const Error * e2)292 static Bool eq_Error ( VgRes res, const Error* e1, const Error* e2 )
293 {
294 if (e1->ekind != e2->ekind)
295 return False;
296 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
297 return False;
298
299 switch (e1->ekind) {
300 //(example code, see comment on CoreSuppKind above)
301 //case ThreadErr:
302 // vg_assert(VG_(needs).core_errors);
303 // return <something>
304 default:
305 if (VG_(needs).tool_errors) {
306 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
307 } else {
308 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
309 "probably needs to be set.\n",
310 (UInt)e1->ekind);
311 VG_(core_panic)("unhandled error type");
312 }
313 }
314 }
315
316
317 /* Helper functions for suppression generation: print a single line of
318 a suppression pseudo-stack-trace, either in XML or text mode. It's
319 important that the behaviour of these two functions exactly
320 corresponds.
321 */
322 #define ERRTXT_LEN 4096
323
printSuppForIp_XML(UInt n,Addr ip,void * uu_opaque)324 static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque)
325 {
326 const HChar *buf;
327 InlIPCursor* iipc = VG_(new_IIPC)(ip);
328 do {
329 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
330 VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf);
331 } else
332 if ( VG_(get_objname)(ip, &buf) ) {
333 VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf);
334 } else {
335 VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n");
336 }
337 } while (VG_(next_IIPC)(iipc));
338 VG_(delete_IIPC)(iipc);
339 }
340
printSuppForIp_nonXML(UInt n,Addr ip,void * textV)341 static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV)
342 {
343 const HChar *buf;
344 XArray* /* of HChar */ text = (XArray*)textV;
345 InlIPCursor* iipc = VG_(new_IIPC)(ip);
346 do {
347 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
348 VG_(xaprintf)(text, " fun:%s\n", buf);
349 } else
350 if ( VG_(get_objname)(ip, &buf) ) {
351 VG_(xaprintf)(text, " obj:%s\n", buf);
352 } else {
353 VG_(xaprintf)(text, " obj:*\n");
354 }
355 } while (VG_(next_IIPC)(iipc));
356 VG_(delete_IIPC)(iipc);
357 }
358
359 /* Generate a suppression for an error, either in text or XML mode.
360 */
gen_suppression(const Error * err)361 static void gen_suppression(const Error* err)
362 {
363 const HChar* name;
364 ExeContext* ec;
365 XArray* /* HChar */ text;
366
367 const HChar* dummy_name = "insert_a_suppression_name_here";
368
369 vg_assert(err);
370
371 ec = VG_(get_error_where)(err);
372 vg_assert(ec);
373
374 name = VG_TDICT_CALL(tool_get_error_name, err);
375 if (NULL == name) {
376 VG_(umsg)("(%s does not allow error to be suppressed)\n",
377 VG_(details).name);
378 return;
379 }
380
381 /* In XML mode, we also need to print the plain text version of the
382 suppresion in a CDATA section. What that really means is, we
383 need to generate the plaintext version both in XML and text
384 mode. So generate it into TEXT. */
385 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1",
386 VG_(free), sizeof(HChar) );
387
388 /* Ok. Generate the plain text version into TEXT. */
389 VG_(xaprintf)(text, "{\n");
390 VG_(xaprintf)(text, " <%s>\n", dummy_name);
391 VG_(xaprintf)(text, " %s:%s\n", VG_(details).name, name);
392
393 HChar *xtra = NULL;
394 SizeT xtra_size = 0;
395 SizeT num_written;
396
397 do {
398 xtra_size += 256;
399 xtra = VG_(realloc)("errormgr.gen_suppression.2", xtra,xtra_size);
400 num_written = VG_TDICT_CALL(tool_get_extra_suppression_info,
401 err, xtra, xtra_size);
402 } while (num_written == xtra_size); // resize buffer and retry
403
404 // Ensure buffer is properly terminated
405 vg_assert(xtra[num_written] == '\0');
406
407 if (num_written)
408 VG_(xaprintf)(text, " %s\n", xtra);
409
410 // Print stack trace elements
411 UInt n_ips = VG_(get_ExeContext_n_ips)(ec);
412 vg_assert(n_ips > 0);
413 vg_assert(n_ips <= VG_DEEPEST_BACKTRACE);
414 VG_(apply_StackTrace)(printSuppForIp_nonXML,
415 text,
416 VG_(get_ExeContext_StackTrace)(ec),
417 n_ips);
418
419 VG_(xaprintf)(text, "}\n");
420 // zero terminate
421 VG_(xaprintf)(text, "%c", (HChar)0 );
422 // VG_(printf) of text
423
424 /* And now display it. */
425 if (! VG_(clo_xml) ) {
426
427 // the simple case
428 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
429
430 } else {
431
432 /* Now we have to print the XML directly. No need to go to the
433 effort of stuffing it in an XArray, since we won't need it
434 again. */
435 VG_(printf_xml)(" <suppression>\n");
436 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name);
437 VG_(printf_xml)(
438 " <skind>%pS:%pS</skind>\n", VG_(details).name, name);
439 if (num_written)
440 VG_(printf_xml)(" <skaux>%pS</skaux>\n", xtra);
441
442 // Print stack trace elements
443 VG_(apply_StackTrace)(printSuppForIp_XML,
444 NULL,
445 VG_(get_ExeContext_StackTrace)(ec),
446 VG_(get_ExeContext_n_ips)(ec));
447
448 // And now the cdata bit
449 // XXX FIXME! properly handle the case where the raw text
450 // itself contains "]]>", as specified in Protocol 4.
451 VG_(printf_xml)(" <rawtext>\n");
452 VG_(printf_xml)("<![CDATA[\n");
453 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) );
454 VG_(printf_xml)("]]>\n");
455 VG_(printf_xml)(" </rawtext>\n");
456 VG_(printf_xml)(" </suppression>\n");
457
458 }
459
460 VG_(deleteXA)(text);
461 VG_(free)(xtra);
462 }
463
464
465 /* Figure out if we want to perform a given action for this error,
466 possibly by asking the user.
467 */
VG_(is_action_requested)468 Bool VG_(is_action_requested) ( const HChar* action, Bool* clo )
469 {
470 HChar ch, ch2;
471 Int res;
472
473 /* First off, we shouldn't be asking the user anything if
474 we're in XML mode. */
475 if (VG_(clo_xml))
476 return False; /* That's a Nein, oder Nay as they say down here in B-W */
477
478 if (*clo == False)
479 return False;
480
481 VG_(umsg)("\n");
482
483 again:
484 VG_(printf)(
485 "==%d== "
486 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
487 VG_(getpid)(), action
488 );
489
490 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
491 if (res != 1) goto ioerror;
492 /* res == 1 */
493 if (ch == '\n') return False;
494 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
495 && ch != 'C' && ch != 'c') goto again;
496
497 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
498 if (res != 1) goto ioerror;
499 if (ch2 != '\n') goto again;
500
501 /* No, don't want to do action. */
502 if (ch == 'n' || ch == 'N') return False;
503 /* Yes, want to do action. */
504 if (ch == 'y' || ch == 'Y') return True;
505 /* No, don't want to do action, and don't ask again either. */
506 vg_assert(ch == 'c' || ch == 'C');
507
508 ioerror:
509 *clo = False;
510 return False;
511 }
512
513
514 /* Do text-mode actions on error, that is, immediately after an error
515 is printed. These are:
516 * possibly, call the GDB server
517 * possibly, generate a suppression.
518 Note this should not be called in XML mode!
519 */
520 static
do_actions_on_error(const Error * err,Bool allow_db_attach)521 void do_actions_on_error(const Error* err, Bool allow_db_attach)
522 {
523 Bool still_noisy = True;
524
525 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
526 if (VG_(clo_vgdb) != Vg_VgdbNo
527 && allow_db_attach
528 && VG_(dyn_vgdb_error) <= n_errs_shown) {
529 VG_(umsg)("(action on error) vgdb me ... \n");
530 VG_(gdbserver)( err->tid );
531 VG_(umsg)("Continuing ...\n");
532 }
533
534 /* Or maybe we want to generate the error's suppression? */
535 if (VG_(clo_gen_suppressions) == 2
536 || (VG_(clo_gen_suppressions) == 1
537 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
538 ) {
539 gen_suppression(err);
540 }
541 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
542 VG_(clo_gen_suppressions) = 0;
543 }
544
545
546 /* Prints an error. Not entirely simple because of the differences
547 between XML and text mode output.
548
549 In XML mode:
550
551 * calls the tool's pre-show method, so the tool can create any
552 preamble ahead of the message, if it wants.
553
554 * prints the opening tag, and the <unique> and <tid> fields
555
556 * prints the tool-specific parts of the message
557
558 * if suppression generation is required, a suppression
559
560 * the closing tag
561
562 In text mode:
563
564 * calls the tool's pre-show method, so the tool can create any
565 preamble ahead of the message, if it wants.
566
567 * prints the tool-specific parts of the message
568
569 * calls do_actions_on_error. This optionally does a gdbserver call
570 and optionally prints a suppression; both of these may require user input.
571 */
pp_Error(const Error * err,Bool allow_db_attach,Bool xml)572 static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml )
573 {
574 /* If this fails, you probably specified your tool's method
575 dictionary incorrectly. */
576 vg_assert(VG_(needs).tool_errors);
577
578 if (xml) {
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>%u</tid>\n", err->tid);
594 ThreadState* tst = VG_(get_ThreadState)(err->tid);
595 if (tst->thread_name) {
596 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name);
597 }
598
599 /* actually print it */
600 VG_TDICT_CALL( tool_pp_Error, err );
601
602 if (VG_(clo_gen_suppressions) > 0)
603 gen_suppression(err);
604
605 /* postamble */
606 VG_(printf_xml)("</error>\n");
607 VG_(printf_xml)("\n");
608
609 } else {
610
611 if (VG_(clo_error_markers)[0])
612 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]);
613 VG_TDICT_CALL( tool_before_pp_Error, err );
614
615 if (VG_(tdict).tool_show_ThreadIDs_for_errors
616 && err->tid > 0 && err->tid != last_tid_printed) {
617 ThreadState* tst = VG_(get_ThreadState)(err->tid);
618 if (tst->thread_name) {
619 VG_(umsg)("Thread %u %s:\n", err->tid, tst->thread_name );
620 } else {
621 VG_(umsg)("Thread %u:\n", err->tid );
622 }
623 last_tid_printed = err->tid;
624 }
625
626 VG_TDICT_CALL( tool_pp_Error, err );
627 VG_(umsg)("\n");
628 if (VG_(clo_error_markers)[1])
629 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]);
630
631 }
632
633 do_actions_on_error(err, allow_db_attach);
634 }
635
636
637 /* Construct an error */
638 static
construct_error(Error * err,ThreadId tid,ErrorKind ekind,Addr a,const HChar * s,void * extra,ExeContext * where)639 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
640 const HChar* s, void* extra, ExeContext* where )
641 {
642 /* DO NOT MAKE unique_counter NON-STATIC */
643 static UInt unique_counter = 0;
644
645 vg_assert(tid < VG_N_THREADS);
646
647 /* Core-only parts */
648 err->unique = unique_counter++;
649 err->next = NULL;
650 err->supp = NULL;
651 err->count = 1;
652 err->tid = tid;
653 if (NULL == where)
654 err->where = VG_(record_ExeContext)( tid, 0 );
655 else
656 err->where = where;
657
658 /* Tool-relevant parts */
659 err->ekind = ekind;
660 err->addr = a;
661 err->extra = extra;
662 err->string = s;
663
664 /* sanity... */
665 vg_assert( tid < VG_N_THREADS );
666 }
667
668
669
670 /* Top-level entry point to the error management subsystem.
671 All detected errors are notified here; this routine decides if/when the
672 user should see the error. */
VG_(maybe_record_error)673 void VG_(maybe_record_error) ( ThreadId tid,
674 ErrorKind ekind, Addr a,
675 const HChar* s, void* extra )
676 {
677 Error err;
678 Error* p;
679 Error* p_prev;
680 UInt extra_size;
681 VgRes exe_res = Vg_MedRes;
682 static Bool stopping_message = False;
683 static Bool slowdown_message = False;
684
685 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
686 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
687 have been found, just refuse to collect any more. This stops
688 the burden of the error-management system becoming excessive in
689 extremely buggy programs, although it does make it pretty
690 pointless to continue the Valgrind run after this point. */
691 if (VG_(clo_error_limit)
692 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
693 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
694 && !VG_(clo_xml)) {
695 if (!stopping_message) {
696 VG_(umsg)("\n");
697
698 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
699 VG_(umsg)(
700 "More than %d different errors detected. "
701 "I'm not reporting any more.\n",
702 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
703 } else {
704 VG_(umsg)(
705 "More than %d total errors detected. "
706 "I'm not reporting any more.\n",
707 M_COLLECT_NO_ERRORS_AFTER_FOUND );
708 }
709
710 VG_(umsg)("Final error counts will be inaccurate. "
711 "Go fix your program!\n");
712 VG_(umsg)("Rerun with --error-limit=no to disable "
713 "this cutoff. Note\n");
714 VG_(umsg)("that errors may occur in your program without "
715 "prior warning from\n");
716 VG_(umsg)("Valgrind, because errors are no longer "
717 "being displayed.\n");
718 VG_(umsg)("\n");
719 stopping_message = True;
720 }
721 return;
722 }
723
724 /* Ignore it if error acquisition is disabled for this thread. */
725 { ThreadState* tst = VG_(get_ThreadState)(tid);
726 if (tst->err_disablement_level > 0)
727 return;
728 }
729
730 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
731 been found, be much more conservative about collecting new
732 ones. */
733 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
734 && !VG_(clo_xml)) {
735 exe_res = Vg_LowRes;
736 if (!slowdown_message) {
737 VG_(umsg)("\n");
738 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
739 M_COLLECT_ERRORS_SLOWLY_AFTER);
740 VG_(umsg)("will still be recorded, but in less "
741 "detail than before.\n");
742 slowdown_message = True;
743 }
744 }
745
746 /* Build ourselves the error */
747 construct_error ( &err, tid, ekind, a, s, extra, NULL );
748
749 /* First, see if we've got an error record matching this one. */
750 em_errlist_searches++;
751 p = errors;
752 p_prev = NULL;
753 while (p != NULL) {
754 em_errlist_cmps++;
755 if (eq_Error(exe_res, p, &err)) {
756 /* Found it. */
757 p->count++;
758 if (p->supp != NULL) {
759 /* Deal correctly with suppressed errors. */
760 p->supp->count++;
761 n_errs_suppressed++;
762 } else {
763 n_errs_found++;
764 }
765
766 /* Move p to the front of the list so that future searches
767 for it are faster. It also allows to print the last
768 error (see VG_(show_last_error). */
769 if (p_prev != NULL) {
770 vg_assert(p_prev->next == p);
771 p_prev->next = p->next;
772 p->next = errors;
773 errors = p;
774 }
775
776 return;
777 }
778 p_prev = p;
779 p = p->next;
780 }
781
782 /* Didn't see it. Copy and add. */
783
784 /* OK, we're really going to collect it. The context is on the stack and
785 will disappear shortly, so we must copy it. First do the main
786 (non-'extra') part.
787
788 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
789 is for when there are more details to fill in which take time to work
790 out but don't affect our earlier decision to include the error -- by
791 postponing those details until now, we avoid the extra work in the
792 case where we ignore the error. Ugly.
793
794 Then, if there is an 'extra' part, copy it too, using the size that
795 VG_(tdict).tool_update_extra returned. Also allow for people using
796 the void* extra field for a scalar value like an integer.
797 */
798
799 /* copy main part */
800 p = VG_(malloc)("errormgr.mre.1", sizeof(Error));
801 *p = err;
802
803 /* update 'extra' */
804 switch (ekind) {
805 //(example code, see comment on CoreSuppKind above)
806 //case ThreadErr:
807 // vg_assert(VG_(needs).core_errors);
808 // extra_size = <something>
809 // break;
810 default:
811 vg_assert(VG_(needs).tool_errors);
812 extra_size = VG_TDICT_CALL(tool_update_extra, p);
813 break;
814 }
815
816 /* copy the error string, if there is one.
817 note: if we would have many errors with big strings, using a
818 DedupPoolAlloc for these strings will avoid duplicating
819 such string in each error using it. */
820 if (NULL != p->string) {
821 p->string = VG_(strdup)("errormgr.mre.2", p->string);
822 }
823
824 /* copy block pointed to by 'extra', if there is one */
825 if (NULL != p->extra && 0 != extra_size) {
826 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size);
827 VG_(memcpy)(new_extra, p->extra, extra_size);
828 p->extra = new_extra;
829 }
830
831 p->next = errors;
832 p->supp = is_suppressible_error(&err);
833 errors = p;
834 if (p->supp == NULL) {
835 /* update stats */
836 n_err_contexts++;
837 n_errs_found++;
838 n_errs_shown++;
839 /* Actually show the error; more complex than you might think. */
840 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
841 } else {
842 n_supp_contexts++;
843 n_errs_suppressed++;
844 p->supp->count++;
845 }
846 }
847
848 /* Second top-level entry point to the error management subsystem, for
849 errors that the tool wants to report immediately, eg. because they're
850 guaranteed to only happen once. This avoids all the recording and
851 comparing stuff. But they can be suppressed; returns True if it is
852 suppressed. Bool 'print_error' dictates whether to print the error.
853 Bool 'count_error' dictates whether to count the error in n_errs_found.
854 */
VG_(unique_error)855 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
856 void* extra, ExeContext* where, Bool print_error,
857 Bool allow_db_attach, Bool count_error )
858 {
859 Error err;
860 Supp *su;
861
862 /* Ignore it if error acquisition is disabled for this thread. */
863 ThreadState* tst = VG_(get_ThreadState)(tid);
864 if (tst->err_disablement_level > 0)
865 return False; /* ignored, not suppressed */
866
867 /* Build ourselves the error */
868 construct_error ( &err, tid, ekind, a, s, extra, where );
869
870 /* Unless it's suppressed, we're going to show it. Don't need to make
871 a copy, because it's only temporary anyway.
872
873 Then update the 'extra' part with VG_(tdict).tool_update_extra),
874 because that can have an affect on whether it's suppressed. Ignore
875 the size return value of VG_(tdict).tool_update_extra, because we're
876 not copying 'extra'. Similarly, 's' is also not copied. */
877 (void)VG_TDICT_CALL(tool_update_extra, &err);
878
879 su = is_suppressible_error(&err);
880 if (NULL == su) {
881 if (count_error) {
882 n_errs_found++;
883 n_err_contexts++;
884 }
885
886 if (print_error) {
887 /* update stats */
888 n_errs_shown++;
889 /* Actually show the error; more complex than you might think. */
890 pp_Error(&err, allow_db_attach, VG_(clo_xml));
891 }
892 return False;
893
894 } else {
895 if (count_error) {
896 n_errs_suppressed++;
897 n_supp_contexts++;
898 }
899 su->count++;
900 return True;
901 }
902 }
903
904
905 /*------------------------------------------------------------*/
906 /*--- Exported fns ---*/
907 /*------------------------------------------------------------*/
908
909 /* Show the used suppressions. Returns False if no suppression
910 got used. */
show_used_suppressions(void)911 static Bool show_used_suppressions ( void )
912 {
913 Supp *su;
914 Bool any_supp;
915
916 if (VG_(clo_xml))
917 VG_(printf_xml)("<suppcounts>\n");
918
919 any_supp = False;
920 for (su = suppressions; su != NULL; su = su->next) {
921 if (su->count <= 0)
922 continue;
923 if (VG_(clo_xml)) {
924 VG_(printf_xml)( " <pair>\n"
925 " <count>%d</count>\n"
926 " <name>%pS</name>\n"
927 " </pair>\n",
928 su->count, su->sname );
929 } else {
930 HChar *xtra = NULL;
931 Int xtra_size = 0;
932 SizeT num_written;
933 // blank line before the first shown suppression, if any
934 if (!any_supp)
935 VG_(dmsg)("\n");
936
937 do {
938 xtra_size += 256;
939 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
940 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
941 su, xtra, xtra_size);
942 } while (num_written == xtra_size); // resize buffer and retry
943
944 // Ensure buffer is properly terminated
945 vg_assert(xtra[num_written] == '\0');
946
947 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
948 su->clo_suppressions_i);
949 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
950 filename,
951 su->sname_lineno,
952 num_written ? " " : "", xtra);
953 VG_(free)(xtra);
954 }
955 any_supp = True;
956 }
957
958 if (VG_(clo_xml))
959 VG_(printf_xml)("</suppcounts>\n");
960
961 return any_supp;
962 }
963
964 /* Show all the errors that occurred, and possibly also the
965 suppressions used. */
VG_(show_all_errors)966 void VG_(show_all_errors) ( Int verbosity, Bool xml )
967 {
968 Int i, n_min;
969 Error *p, *p_min;
970 Bool any_supp;
971
972 if (verbosity == 0)
973 return;
974
975 /* If we're printing XML, just show the suppressions and stop. */
976 if (xml) {
977 (void)show_used_suppressions();
978 return;
979 }
980
981 /* We only get here if not printing XML. */
982 VG_(umsg)("ERROR SUMMARY: "
983 "%u errors from %u contexts (suppressed: %u from %u)\n",
984 n_errs_found, n_err_contexts,
985 n_errs_suppressed, n_supp_contexts );
986
987 if (verbosity <= 1)
988 return;
989
990 // We do the following only at -v or above, and only in non-XML
991 // mode
992
993 /* Print the contexts in order of increasing error count.
994 Once an error is shown, we add a huge value to its count to filter it
995 out.
996 After having shown all errors, we reset count to the original value. */
997 for (i = 0; i < n_err_contexts; i++) {
998 n_min = (1 << 30) - 1;
999 p_min = NULL;
1000 for (p = errors; p != NULL; p = p->next) {
1001 if (p->supp != NULL) continue;
1002 if (p->count < n_min) {
1003 n_min = p->count;
1004 p_min = p;
1005 }
1006 }
1007 // XXX: this isn't right. See bug 203651.
1008 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
1009
1010 VG_(umsg)("\n");
1011 VG_(umsg)("%d errors in context %d of %u:\n",
1012 p_min->count, i+1, n_err_contexts);
1013 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
1014
1015 // We're not printing XML -- we'd have exited above if so.
1016 vg_assert(! xml);
1017
1018 if ((i+1 == VG_(clo_dump_error))) {
1019 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
1020 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
1021 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
1022 /*bbs_done*/0,
1023 /*allow redir?*/True);
1024 }
1025
1026 p_min->count = p_min->count + (1 << 30);
1027 }
1028
1029 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1030 for (p = errors; p != NULL; p = p->next) {
1031 if (p->count >= (1 << 30))
1032 p->count = p->count - (1 << 30);
1033 }
1034
1035
1036 any_supp = show_used_suppressions();
1037
1038 if (any_supp)
1039 VG_(umsg)("\n");
1040 // reprint this, so users don't have to scroll way up to find
1041 // the first printing
1042 VG_(umsg)("ERROR SUMMARY: "
1043 "%u errors from %u contexts (suppressed: %u from %u)\n",
1044 n_errs_found, n_err_contexts, n_errs_suppressed,
1045 n_supp_contexts );
1046 }
1047
VG_(show_last_error)1048 void VG_(show_last_error) ( void )
1049 {
1050 if (n_err_contexts == 0) {
1051 VG_(umsg)("No errors yet\n");
1052 return;
1053 }
1054
1055 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
1056 }
1057
1058
1059 /* Show occurrence counts of all errors, in XML form. */
VG_(show_error_counts_as_XML)1060 void VG_(show_error_counts_as_XML) ( void )
1061 {
1062 Error* err;
1063 VG_(printf_xml)("<errorcounts>\n");
1064 for (err = errors; err != NULL; err = err->next) {
1065 if (err->supp != NULL)
1066 continue;
1067 if (err->count <= 0)
1068 continue;
1069 VG_(printf_xml)(" <pair>\n");
1070 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1071 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1072 VG_(printf_xml)(" </pair>\n");
1073 }
1074 VG_(printf_xml)("</errorcounts>\n");
1075 VG_(printf_xml)("\n");
1076 }
1077
1078
1079 /*------------------------------------------------------------*/
1080 /*--- Suppression parsing ---*/
1081 /*------------------------------------------------------------*/
1082
1083 /* Get the next char from fd into *out_buf. Returns 1 if success,
1084 0 if eof or < 0 if error. */
1085
get_char(Int fd,HChar * out_buf)1086 static Int get_char ( Int fd, HChar* out_buf )
1087 {
1088 Int r;
1089 static HChar buf[256];
1090 static Int buf_size = 0;
1091 static Int buf_used = 0;
1092 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1093 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1094 if (buf_used == buf_size) {
1095 r = VG_(read)(fd, buf, sizeof buf);
1096 if (r < 0) return r; /* read failed */
1097 vg_assert(r >= 0 && r <= sizeof buf);
1098 buf_size = r;
1099 buf_used = 0;
1100 }
1101 if (buf_size == 0)
1102 return 0; /* eof */
1103 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1104 vg_assert(buf_used >= 0 && buf_used < buf_size);
1105 *out_buf = buf[buf_used];
1106 buf_used++;
1107 return 1;
1108 }
1109
1110 // Get a non blank non comment line.
1111 // Returns True if eof.
get_nbnc_line(Int fd,HChar ** bufpp,SizeT * nBufp,Int * lineno)1112 static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1113 {
1114 HChar* buf = *bufpp;
1115 SizeT nBuf = *nBufp;
1116 HChar ch;
1117 Int n, i;
1118
1119 vg_assert(lineno); // lineno needed to correctly track line numbers.
1120
1121 while (True) {
1122 buf[0] = 0;
1123 /* First, read until a non-blank char appears. */
1124 while (True) {
1125 n = get_char(fd, &ch);
1126 if (n == 1 && !VG_(isspace)(ch)) break;
1127 if (n == 1 && ch == '\n')
1128 (*lineno)++;
1129 if (n <= 0) return True;
1130 }
1131
1132 /* Now, read the line into buf. */
1133 i = 0;
1134 buf[i++] = ch; buf[i] = 0;
1135 while (True) {
1136 n = get_char(fd, &ch);
1137 if (n <= 0) return False; /* the next call will return True */
1138 if (ch == '\n')
1139 (*lineno)++;
1140 if (ch == '\n') break;
1141 if (i > 0 && i == nBuf-1) {
1142 *nBufp = nBuf = nBuf * 2;
1143 #define RIDICULOUS 100000
1144 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1145 "VG_(get_line): line longer than %d chars, aborting\n",
1146 RIDICULOUS);
1147 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1148 }
1149 buf[i++] = ch; buf[i] = 0;
1150 }
1151 while (i > 1 && VG_(isspace)(buf[i-1])) {
1152 i--; buf[i] = 0;
1153 };
1154
1155 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
1156 /* Ok, we have a line. If a non-comment line, return.
1157 If a comment line, start all over again. */
1158 if (buf[0] != '#') return False;
1159 }
1160 }
1161
1162 // True if buf starts with fun: or obj: or is ...
is_location_line(const HChar * buf)1163 static Bool is_location_line (const HChar* buf)
1164 {
1165 return VG_(strncmp)(buf, "fun:", 4) == 0
1166 || VG_(strncmp)(buf, "obj:", 4) == 0
1167 || VG_(strcmp)(buf, "...") == 0;
1168 }
1169
VG_(get_line)1170 Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1171 {
1172 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1173
1174 if (eof)
1175 return True;
1176
1177 if (is_location_line(*bufpp))
1178 return True; // Not a extra suppr line
1179 else
1180 return False; // A suppression extra line
1181 }
1182
1183 /* True if s contains no wildcard (?, *) characters. */
is_simple_str(const HChar * s)1184 static Bool is_simple_str (const HChar *s)
1185 {
1186 while (*s) {
1187 if (*s == '?' || *s == '*')
1188 return False;
1189 s++;
1190 }
1191 return True;
1192 }
1193
1194 /* buf contains the raw name of a caller, supposedly either
1195 fun:some_function_name or
1196 obj:some_object_name or
1197 ...
1198 Set p->ty and p->name accordingly.
1199 p->name is allocated and set to the string
1200 after the descriptor (fun: or obj:) part.
1201 Returns False if failed.
1202 */
setLocationTy(SuppLoc * p,const HChar * buf)1203 static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
1204 {
1205 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
1206 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
1207 p->name_is_simple_str = is_simple_str (p->name);
1208 p->ty = FunName;
1209 return True;
1210 }
1211 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
1212 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
1213 p->name_is_simple_str = is_simple_str (p->name);
1214 p->ty = ObjName;
1215 return True;
1216 }
1217 if (VG_(strcmp)(buf, "...") == 0) {
1218 p->name = NULL;
1219 p->name_is_simple_str = False;
1220 p->ty = DotDotDot;
1221 return True;
1222 }
1223 VG_(printf)("location should be \"...\", or should start "
1224 "with \"fun:\" or \"obj:\"\n");
1225 return False;
1226 }
1227
1228
1229 /* Look for "tool" in a string like "tool1,tool2,tool3" */
tool_name_present(const HChar * name,const HChar * names)1230 static Bool tool_name_present(const HChar *name, const HChar *names)
1231 {
1232 Bool found;
1233 HChar *s = NULL; /* Shut gcc up */
1234 Int len = VG_(strlen)(name);
1235
1236 found = (NULL != (s = VG_(strstr)(names, name)) &&
1237 (s == names || *(s-1) == ',') &&
1238 (*(s+len) == ',' || *(s+len) == '\0')
1239 );
1240
1241 return found;
1242 }
1243
1244 /* Read suppressions from the file specified in
1245 VG_(clo_suppressions)[clo_suppressions_i]
1246 and place them in the suppressions list. If there's any difficulty
1247 doing this, just give up -- there's no point in trying to recover.
1248 */
load_one_suppressions_file(Int clo_suppressions_i)1249 static void load_one_suppressions_file ( Int clo_suppressions_i )
1250 {
1251 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1252 clo_suppressions_i);
1253 SysRes sres;
1254 Int fd, i, j, lineno = 0;
1255 Bool got_a_location_line_read_by_tool;
1256 Bool eof;
1257 SizeT nBuf = 200;
1258 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1259 HChar* tool_names;
1260 HChar* supp_name;
1261 const HChar* err_str = NULL;
1262 SuppLoc tmp_callers[VG_DEEPEST_BACKTRACE];
1263
1264 // Check it's not a directory.
1265 if (VG_(is_dir)( filename )) {
1266 if (VG_(clo_xml))
1267 VG_(printf_xml)("</valgrindoutput>\n");
1268 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
1269 VG_(exit)(1);
1270 }
1271
1272 // Open the suppression file.
1273 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
1274 if (sr_isError(sres)) {
1275 if (VG_(clo_xml))
1276 VG_(printf_xml)("</valgrindoutput>\n");
1277 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
1278 VG_(exit)(1);
1279 }
1280 fd = sr_Res(sres);
1281
1282 # define BOMB(S) { err_str = S; goto syntax_error; }
1283
1284 while (True) {
1285 /* Assign and initialise the two suppression halves (core and tool) */
1286 Supp* supp;
1287 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
1288 supp->count = 0;
1289
1290 // Initialise temporary reading-in buffer.
1291 for (i = 0; i < VG_DEEPEST_BACKTRACE; i++) {
1292 tmp_callers[i].ty = NoName;
1293 tmp_callers[i].name_is_simple_str = False;
1294 tmp_callers[i].name = NULL;
1295 }
1296
1297 supp->string = supp->extra = NULL;
1298
1299 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1300 if (eof) {
1301 VG_(free)(supp);
1302 break;
1303 }
1304
1305 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
1306
1307 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1308
1309 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1310
1311 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
1312 supp->clo_suppressions_i = clo_suppressions_i;
1313 supp->sname_lineno = lineno;
1314
1315 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1316
1317 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
1318
1319 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
1320 i = 0;
1321 while (True) {
1322 if (buf[i] == ':') break;
1323 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
1324 i++;
1325 }
1326 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1327
1328 tool_names = & buf[0];
1329 supp_name = & buf[i+1];
1330
1331 if (VG_(needs).core_errors && tool_name_present("core", tool_names))
1332 {
1333 // A core suppression
1334 //(example code, see comment on CoreSuppKind above)
1335 //if (VG_STREQ(supp_name, "Thread"))
1336 // supp->skind = ThreadSupp;
1337 //else
1338 BOMB("unknown core suppression type");
1339 }
1340 else if (VG_(needs).tool_errors &&
1341 tool_name_present(VG_(details).name, tool_names))
1342 {
1343 // A tool suppression
1344 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
1345 /* Do nothing, function fills in supp->skind */
1346 } else {
1347 BOMB("unknown tool suppression type");
1348 }
1349 }
1350 else {
1351 // Ignore rest of suppression
1352 while (True) {
1353 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1354 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
1355 if (VG_STREQ(buf, "}"))
1356 break;
1357 }
1358 VG_(free)(supp->sname);
1359 VG_(free)(supp);
1360 continue;
1361 }
1362
1363 buf[0] = 0;
1364 // tool_read_extra_suppression_info might read lines
1365 // from fd till a location line.
1366 if (VG_(needs).tool_errors &&
1367 !VG_TDICT_CALL(tool_read_extra_suppression_info,
1368 fd, &buf, &nBuf, &lineno, supp))
1369 {
1370 BOMB("bad or missing extra suppression info");
1371 }
1372
1373 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1374
1375 /* the main frame-descriptor reading loop */
1376 i = 0;
1377 while (True) {
1378 if (got_a_location_line_read_by_tool) {
1379 got_a_location_line_read_by_tool = False;
1380 eof = False;
1381 } else {
1382 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1383 }
1384 if (eof)
1385 BOMB("unexpected end-of-file (when reading stack trace)");
1386 if (VG_STREQ(buf, "}")) {
1387 if (i > 0) {
1388 break;
1389 } else {
1390 BOMB("missing stack trace");
1391 }
1392 }
1393 if (i == VG_DEEPEST_BACKTRACE)
1394 BOMB("too many callers in stack trace");
1395 if (i > 0 && i >= VG_(clo_backtrace_size))
1396 break;
1397 if (!setLocationTy(&(tmp_callers[i]), buf))
1398 BOMB("location should be \"...\", or should start "
1399 "with \"fun:\" or \"obj:\"");
1400 i++;
1401 }
1402
1403 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1404 // lines and grab the '}'.
1405 if (!VG_STREQ(buf, "}")) {
1406 do {
1407 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1408 } while (!eof && !VG_STREQ(buf, "}"));
1409 }
1410
1411 // Reject entries which are entirely composed of frame
1412 // level wildcards.
1413 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1414 for (j = 0; j < i; j++) {
1415 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName)
1416 break;
1417 vg_assert(tmp_callers[j].ty == DotDotDot);
1418 }
1419 vg_assert(j >= 0 && j <= i);
1420 if (j == i) {
1421 // we didn't find any non-"..." entries
1422 BOMB("suppression must contain at least one location "
1423 "line which is not \"...\"");
1424 }
1425
1426 // Copy tmp_callers[] into supp->callers[]
1427 supp->n_callers = i;
1428 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
1429 for (i = 0; i < supp->n_callers; i++) {
1430 supp->callers[i] = tmp_callers[i];
1431 }
1432
1433 supp->next = suppressions;
1434 suppressions = supp;
1435 }
1436 VG_(free)(buf);
1437 VG_(close)(fd);
1438 return;
1439
1440 syntax_error:
1441 if (VG_(clo_xml))
1442 VG_(printf_xml)("</valgrindoutput>\n");
1443 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
1444 filename, lineno );
1445 VG_(umsg)(" %s\n", err_str );
1446
1447 VG_(close)(fd);
1448 VG_(umsg)("exiting now.\n");
1449 VG_(exit)(1);
1450
1451 # undef BOMB
1452 }
1453
1454
VG_(load_suppressions)1455 void VG_(load_suppressions) ( void )
1456 {
1457 Int i;
1458 suppressions = NULL;
1459 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
1460 if (VG_(clo_verbosity) > 1) {
1461 VG_(dmsg)("Reading suppressions file: %s\n",
1462 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
1463 }
1464 load_one_suppressions_file( i );
1465 }
1466 }
1467
1468
1469 /*------------------------------------------------------------*/
1470 /*--- Matching errors to suppressions ---*/
1471 /*------------------------------------------------------------*/
1472
1473 /* Parameterising functions for the use of VG_(generic_match) in
1474 suppression-vs-error matching. The suppression frames (SuppLoc)
1475 play the role of 'pattern'-element, and the error frames (IPs,
1476 hence simply Addrs) play the role of 'input'. In short then, we're
1477 matching a sequence of Addrs against a pattern composed of a
1478 sequence of SuppLocs.
1479 */
supploc_IsStar(const void * supplocV)1480 static Bool supploc_IsStar ( const void* supplocV )
1481 {
1482 const SuppLoc* supploc = supplocV;
1483 return supploc->ty == DotDotDot;
1484 }
1485
supploc_IsQuery(const void * supplocV)1486 static Bool supploc_IsQuery ( const void* supplocV )
1487 {
1488 return False; /* there's no '?' equivalent in the supp syntax */
1489 }
1490
1491 /* IPtoFunOrObjCompleter is a lazy completer of the IPs
1492 needed to match an error with the suppression patterns.
1493 The matching between an IP and a suppression pattern is done either
1494 with the IP function name or with the IP object name.
1495 First time the fun or obj name is needed for an IP member
1496 of a stack trace, it will be computed and stored in names.
1497 Also, if the IP corresponds to one or more inlined function calls,
1498 the inlined function names are expanded.
1499 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1500 allocations and the nr of debuginfo search. */
1501 typedef
1502 struct {
1503 StackTrace ips; // stack trace we are lazily completing.
1504 UWord n_ips; // nr of elements in ips.
1505
1506 // VG_(generic_match) calls haveInputInpC to check
1507 // for the presence of an input element identified by ixInput
1508 // (i.e. a number that identifies the ixInput element of the
1509 // input sequence). It calls supp_pattEQinp to match this input
1510 // element with a pattern.
1511 // When inlining info is used to provide inlined function calls
1512 // in stacktraces, one IP in ips can be expanded in several
1513 // function names. So, each time input (or presence of input)
1514 // is requested by VG_(generic_match), we will expand
1515 // more IP of ips till we have expanded enough to reach the
1516 // input element requested (or we cannot expand anymore).
1517
1518 UWord n_ips_expanded;
1519 // n_ips_expanded maintains the nr of elements in ips that we have
1520 // already expanded.
1521 UWord n_expanded;
1522 // n_expanded maintains the nr of elements resulting from the expansion
1523 // of the n_ips_expanded IPs. Without inlined function calls,
1524 // n_expanded == n_ips_expanded. With inlining info,
1525 // n_expanded >= n_ips_expanded.
1526
1527 Int* n_offsets_per_ip;
1528 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1529 // obj_offsets resulting of the expansion of ips[i].
1530 // The sum of all n_expanded_per_ip must be equal to n_expanded.
1531 // This array allows to retrieve the position in ips corresponding to
1532 // an ixInput.
1533
1534 // size (in elements) of fun_offsets and obj_offsets.
1535 // (fun|obj)_offsets are reallocated if more space is needed
1536 // to expand an IP.
1537 UWord sz_offsets;
1538
1539 Int* fun_offsets;
1540 // fun_offsets[ixInput] is the offset in names where the
1541 // function name for the ixInput element of the input sequence
1542 // can be found. As one IP of ips can be expanded in several
1543 // function calls due to inlined function calls, we can have more
1544 // elements in fun_offsets than in ips.
1545 // An offset -1 means the function name has not yet been computed.
1546 Int* obj_offsets;
1547 // Similarly, obj_offsets[ixInput] gives the offset for the
1548 // object name for ips[ixInput]
1549 // (-1 meaning object name not yet been computed).
1550
1551 // All function names and object names will be concatenated
1552 // in names. names is reallocated on demand.
1553 HChar *names;
1554 Int names_szB; // size of names.
1555 Int names_free; // offset first free HChar in names.
1556 }
1557 IPtoFunOrObjCompleter;
1558
pp_ip2fo(const IPtoFunOrObjCompleter * ip2fo)1559 static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
1560 {
1561 Int i, j;
1562 Int o;
1563
1564 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1565 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1566 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1567 o = 0;
1568 for (j = 0; j < i; j++)
1569 o += ip2fo->n_offsets_per_ip[j];
1570 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1571 i, ip2fo->ips[i],
1572 o, o+ip2fo->n_offsets_per_ip[i]-1);
1573 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1574 VG_(printf)("%sfun:%s obj:%s\n",
1575 j == 0 ? "" : " ",
1576 ip2fo->fun_offsets[o+j] == -1 ?
1577 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1578 ip2fo->obj_offsets[o+j] == -1 ?
1579 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1580 }
1581 }
1582 }
1583
1584 /* free the memory in ip2fo.
1585 At debuglog 4, su (or NULL) will be used to show the matching
1586 (or non matching) with ip2fo. */
clearIPtoFunOrObjCompleter(const Supp * su,IPtoFunOrObjCompleter * ip2fo)1587 static void clearIPtoFunOrObjCompleter ( const Supp *su,
1588 IPtoFunOrObjCompleter* ip2fo)
1589 {
1590 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
1591 if (su) {
1592 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1593 su->clo_suppressions_i);
1594 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1595 su->sname,
1596 filename,
1597 su->sname_lineno);
1598 } else
1599 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1600 VG_(pp_StackTrace) (ip2fo->ips, ip2fo->n_ips);
1601 pp_ip2fo(ip2fo);
1602 }
1603 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1604 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1605 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1606 if (ip2fo->names) VG_(free)(ip2fo->names);
1607 }
1608
1609 /* Grow ip2fo->names to ensure we have NEEDED characters available
1610 in ip2fo->names and returns a pointer to the first free char. */
grow_names(IPtoFunOrObjCompleter * ip2fo,SizeT needed)1611 static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
1612 {
1613 if (ip2fo->names_szB
1614 < ip2fo->names_free + needed) {
1615 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1616
1617 ip2fo->names
1618 = VG_(realloc)("foc_names",
1619 ip2fo->names,
1620 ip2fo->names_szB + needed);
1621 ip2fo->names_szB += needed;
1622 }
1623 return ip2fo->names + ip2fo->names_free;
1624 }
1625
1626 /* foComplete returns the function name or object name for ixInput.
1627 If needFun, returns the function name for this input
1628 else returns the object name for this input.
1629 The function name or object name will be computed and added in
1630 names if not yet done. */
foComplete(IPtoFunOrObjCompleter * ip2fo,Int ixInput,Bool needFun)1631 static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1632 Int ixInput, Bool needFun)
1633 {
1634 vg_assert (ixInput < ip2fo->n_expanded);
1635 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
1636
1637 // ptr to the offset array for function offsets (if needFun)
1638 // or object offsets (if !needFun).
1639 Int** offsets;
1640 if (needFun)
1641 offsets = &ip2fo->fun_offsets;
1642 else
1643 offsets = &ip2fo->obj_offsets;
1644
1645 // Complete Fun name or Obj name for IP if not yet done.
1646 if ((*offsets)[ixInput] == -1) {
1647 const HChar* caller;
1648
1649 (*offsets)[ixInput] = ip2fo->names_free;
1650 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1651 needFun ? "fun" : "obj",
1652 ixInput, ip2fo->names_free);
1653 if (needFun) {
1654 // With inline info, fn names must have been completed already.
1655 vg_assert (!VG_(clo_read_inline_info));
1656 /* Get the function name into 'caller_name', or "???"
1657 if unknown. */
1658 // Nb: C++-mangled names are used in suppressions. Do, though,
1659 // Z-demangle them, since otherwise it's possible to wind
1660 // up comparing "malloc" in the suppression against
1661 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1662 // two of them need to be made to match.
1663 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->ips[ixInput],
1664 &caller,
1665 NULL))
1666 caller = "???";
1667 } else {
1668 /* Get the object name into 'caller_name', or "???"
1669 if unknown. */
1670 UWord i;
1671 UWord last_expand_pos_ips = 0;
1672 UWord pos_ips;
1673
1674 /* First get the pos in ips corresponding to ixInput */
1675 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1676 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
1677 if (ixInput < last_expand_pos_ips)
1678 break;
1679 }
1680 /* pos_ips is the position in ips corresponding to ixInput.
1681 last_expand_pos_ips is the last offset in fun/obj where
1682 ips[pos_ips] has been expanded. */
1683
1684 if (!VG_(get_objname)(ip2fo->ips[pos_ips], &caller))
1685 caller = "???";
1686
1687 // Have all inlined calls pointing at this object name
1688 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1689 i < last_expand_pos_ips;
1690 i++) {
1691 ip2fo->obj_offsets[i] = ip2fo->names_free;
1692 if (DEBUG_ERRORMGR)
1693 VG_(printf) (" set obj_offset %lu to %d\n",
1694 i, ip2fo->names_free);
1695 }
1696 }
1697 SizeT caller_len = VG_(strlen)(caller);
1698 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1699 VG_(strcpy)(caller_name, caller);
1700 ip2fo->names_free += caller_len + 1;
1701 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
1702 }
1703
1704 return ip2fo->names + (*offsets)[ixInput];
1705 }
1706
1707 // Grow fun and obj _offsets arrays to have at least n_req elements.
1708 // Ensure n_offsets_per_ip is allocated.
grow_offsets(IPtoFunOrObjCompleter * ip2fo,Int n_req)1709 static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1710 {
1711 Int i;
1712
1713 // n_offsets_per_ip must always have the size of the ips array
1714 if (ip2fo->n_offsets_per_ip == NULL) {
1715 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1716 ip2fo->n_ips * sizeof(Int));
1717 for (i = 0; i < ip2fo->n_ips; i++)
1718 ip2fo->n_offsets_per_ip[i] = 0;
1719 }
1720
1721 if (ip2fo->sz_offsets >= n_req)
1722 return;
1723
1724 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1725 // elements and at least a few more elements than the current size.
1726 if (n_req < ip2fo->n_ips)
1727 n_req = ip2fo->n_ips;
1728 if (n_req < ip2fo->sz_offsets + 5)
1729 n_req = ip2fo->sz_offsets + 5;
1730
1731 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1732 n_req * sizeof(Int));
1733 for (i = ip2fo->sz_offsets; i < n_req; i++)
1734 ip2fo->fun_offsets[i] = -1;
1735
1736 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1737 n_req * sizeof(Int));
1738 for (i = ip2fo->sz_offsets; i < n_req; i++)
1739 ip2fo->obj_offsets[i] = -1;
1740
1741 ip2fo->sz_offsets = n_req;
1742 }
1743
1744 // Expands more IPs from ip2fo->ips.
expandInput(IPtoFunOrObjCompleter * ip2fo,UWord ixInput)1745 static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1746 {
1747 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1748 && ip2fo->n_expanded <= ixInput) {
1749 if (VG_(clo_read_inline_info)) {
1750 // Expand one more IP in one or more calls.
1751 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1752 InlIPCursor *iipc;
1753
1754 iipc = VG_(new_IIPC)(IP);
1755 // The only thing we really need is the nr of inlined fn calls
1756 // corresponding to the IP we will expand.
1757 // However, computing this is mostly the same as finding
1758 // the function name. So, let's directly complete the function name.
1759 do {
1760 const HChar *caller;
1761 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1762 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1763 if (!VG_(get_fnname_no_cxx_demangle)(IP,
1764 &caller,
1765 iipc))
1766 caller = "???";
1767 SizeT caller_len = VG_(strlen)(caller);
1768 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1769 VG_(strcpy)(caller_name, caller);
1770 ip2fo->names_free += caller_len + 1;
1771 ip2fo->n_expanded++;
1772 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1773 } while (VG_(next_IIPC)(iipc));
1774 ip2fo->n_ips_expanded++;
1775 VG_(delete_IIPC) (iipc);
1776 } else {
1777 // Without inlined fn call info, expansion simply
1778 // consists in allocating enough elements in (fun|obj)_offsets.
1779 // The function or object names themselves will be completed
1780 // when requested.
1781 Int i;
1782 grow_offsets(ip2fo, ip2fo->n_ips);
1783 ip2fo->n_ips_expanded = ip2fo->n_ips;
1784 ip2fo->n_expanded = ip2fo->n_ips;
1785 for (i = 0; i < ip2fo->n_ips; i++)
1786 ip2fo->n_offsets_per_ip[i] = 1;
1787 }
1788 }
1789 }
1790
haveInputInpC(void * inputCompleter,UWord ixInput)1791 static Bool haveInputInpC (void* inputCompleter, UWord ixInput )
1792 {
1793 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
1794 expandInput(ip2fo, ixInput);
1795 return ixInput < ip2fo->n_expanded;
1796 }
1797
supp_pattEQinp(const void * supplocV,const void * addrV,void * inputCompleter,UWord ixInput)1798 static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
1799 void* inputCompleter, UWord ixInput )
1800 {
1801 const SuppLoc* supploc = supplocV; /* PATTERN */
1802 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
1803 HChar* funobj_name; // Fun or Obj name.
1804 Bool ret;
1805
1806 expandInput(ip2fo, ixInput);
1807 vg_assert(ixInput < ip2fo->n_expanded);
1808
1809 /* So, does this IP address match this suppression-line? */
1810 switch (supploc->ty) {
1811 case DotDotDot:
1812 /* supp_pattEQinp is a callback from VG_(generic_match). As
1813 per the spec thereof (see include/pub_tool_seqmatch.h), we
1814 should never get called with a pattern value for which the
1815 _IsStar or _IsQuery function would return True. Hence
1816 this can't happen. */
1817 vg_assert(0);
1818 case ObjName:
1819 funobj_name = foComplete(ip2fo, ixInput, False /*needFun*/);
1820 break;
1821 case FunName:
1822 funobj_name = foComplete(ip2fo, ixInput, True /*needFun*/);
1823 break;
1824 default:
1825 vg_assert(0);
1826 }
1827
1828 /* So now we have the function or object name in funobj_name, and
1829 the pattern (at the character level) to match against is in
1830 supploc->name. Hence (and leading to a re-entrant call of
1831 VG_(generic_match) if there is a wildcard character): */
1832 if (supploc->name_is_simple_str)
1833 ret = VG_(strcmp) (supploc->name, funobj_name) == 0;
1834 else
1835 ret = VG_(string_match)(supploc->name, funobj_name);
1836 if (DEBUG_ERRORMGR)
1837 VG_(printf) ("supp_pattEQinp %s patt %s ixUnput %lu value:%s match:%s\n",
1838 supploc->ty == FunName ? "fun" : "obj",
1839 supploc->name, ixInput, funobj_name,
1840 ret ? "yes" : "no");
1841 return ret;
1842 }
1843
1844 /////////////////////////////////////////////////////
1845
supp_matches_callers(IPtoFunOrObjCompleter * ip2fo,const Supp * su)1846 static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
1847 const Supp* su)
1848 {
1849 /* Unwrap the args and set up the correct parameterisation of
1850 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1851 supp_pattEQinp. */
1852 /* note, StackTrace ip2fo->ips === Addr* */
1853 SuppLoc* supps = su->callers;
1854 UWord n_supps = su->n_callers;
1855 UWord szbPatt = sizeof(SuppLoc);
1856 Bool matchAll = False; /* we just want to match a prefix */
1857 if (DEBUG_ERRORMGR) {
1858 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1859 su->clo_suppressions_i);
1860 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
1861 su->sname,
1862 filename,
1863 su->sname_lineno);
1864 }
1865 return
1866 VG_(generic_match)(
1867 matchAll,
1868 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
1869 /*INPUT*/
1870 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
1871 0/*initial ixInput*/,
1872 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
1873 ip2fo, haveInputInpC
1874 );
1875 }
1876
1877 /////////////////////////////////////////////////////
1878
1879 static
supp_matches_error(const Supp * su,const Error * err)1880 Bool supp_matches_error(const Supp* su, const Error* err)
1881 {
1882 switch (su->skind) {
1883 //(example code, see comment on CoreSuppKind above)
1884 //case ThreadSupp:
1885 // return (err->ekind == ThreadErr);
1886 default:
1887 if (VG_(needs).tool_errors) {
1888 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
1889 } else {
1890 VG_(printf)(
1891 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
1892 "probably needs to be set.\n",
1893 (UInt)err->ekind);
1894 VG_(core_panic)("unhandled suppression type");
1895 }
1896 }
1897 }
1898
1899 /////////////////////////////////////////////////////
1900
1901 /* Does an error context match a suppression? ie is this a suppressible
1902 error? If so, return a pointer to the Supp record, otherwise NULL.
1903 Tries to minimise the number of symbol searches since they are expensive.
1904 */
is_suppressible_error(const Error * err)1905 static Supp* is_suppressible_error ( const Error* err )
1906 {
1907 Supp* su;
1908 Supp* su_prev;
1909
1910 IPtoFunOrObjCompleter ip2fo;
1911 /* Conceptually, ip2fo contains an array of function names and an array of
1912 object names, corresponding to the array of IP of err->where.
1913 These names are just computed 'on demand' (so once maximum),
1914 then stored (efficiently, avoiding too many allocs) in ip2fo to be
1915 re-usable for the matching of the same IP with the next suppression
1916 pattern.
1917
1918 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
1919 of its arguments. It will then pass it to the function
1920 supp_pattEQinp which will then lazily complete the IP function name or
1921 object name inside ip2fo. Next time the fun or obj name for the same
1922 IP is needed (i.e. for the matching with the next suppr pattern), then
1923 the fun or obj name will not be searched again in the debug info. */
1924
1925 /* stats gathering */
1926 em_supplist_searches++;
1927
1928 /* Prepare the lazy input completer. */
1929 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
1930 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
1931 ip2fo.n_ips_expanded = 0;
1932 ip2fo.n_expanded = 0;
1933 ip2fo.sz_offsets = 0;
1934 ip2fo.n_offsets_per_ip = NULL;
1935 ip2fo.fun_offsets = NULL;
1936 ip2fo.obj_offsets = NULL;
1937 ip2fo.names = NULL;
1938 ip2fo.names_szB = 0;
1939 ip2fo.names_free = 0;
1940
1941 /* See if the error context matches any suppression. */
1942 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
1943 VG_(dmsg)("errormgr matching begin\n");
1944 su_prev = NULL;
1945 for (su = suppressions; su != NULL; su = su->next) {
1946 em_supplist_cmps++;
1947 if (supp_matches_error(su, err)
1948 && supp_matches_callers(&ip2fo, su)) {
1949 /* got a match. */
1950 /* Inform the tool that err is suppressed by su. */
1951 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
1952 /* Move this entry to the head of the list
1953 in the hope of making future searches cheaper. */
1954 if (su_prev) {
1955 vg_assert(su_prev->next == su);
1956 su_prev->next = su->next;
1957 su->next = suppressions;
1958 suppressions = su;
1959 }
1960 clearIPtoFunOrObjCompleter(su, &ip2fo);
1961 return su;
1962 }
1963 su_prev = su;
1964 }
1965 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
1966 return NULL; /* no matches */
1967 }
1968
1969 /* Show accumulated error-list and suppression-list search stats.
1970 */
VG_(print_errormgr_stats)1971 void VG_(print_errormgr_stats) ( void )
1972 {
1973 VG_(dmsg)(
1974 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
1975 em_supplist_searches, em_supplist_cmps
1976 );
1977 VG_(dmsg)(
1978 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
1979 em_errlist_searches, em_errlist_cmps
1980 );
1981 }
1982
1983 /*--------------------------------------------------------------------*/
1984 /*--- end ---*/
1985 /*--------------------------------------------------------------------*/
1986