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