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