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