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