Change LOG to VLOG in ThumbnailTabHelper.
[chromium-blink-merge.git] / tools / heapcheck / suppressions.py
blob506caa670f8d15ae506b89194782953a8b476351
1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Valgrind-style suppressions for heapchecker reports.
8 Suppressions are defined as follows:
10 # optional one-line comments anywhere in the suppressions file.
12 Toolname:Errortype
13 Short description of the error.
14 fun:function_name
15 fun:wildcarded_fun*_name
16 # an ellipsis wildcards zero or more functions in a stack.
17 ...
18 fun:some_other_function_name
21 Note that only a 'fun:' prefix is allowed, i.e. we can't suppress objects and
22 source files.
24 If ran from the command line, suppressions.py does a self-test of the
25 Suppression class.
26 """
28 import re
30 ELLIPSIS = '...'
33 class Suppression(object):
34 """This class represents a single stack trace suppression.
36 Attributes:
37 type: A string representing the error type, e.g. Heapcheck:Leak.
38 description: A string representing the error description.
39 """
41 def __init__(self, kind, description, stack):
42 """Inits Suppression.
44 stack is a list of function names and/or wildcards.
46 Args:
47 kind:
48 description: Same as class attributes.
49 stack: A list of strings.
50 """
51 self.type = kind
52 self.description = description
53 self._stack = stack
54 re_line = ''
55 re_bucket = ''
56 for line in stack:
57 if line == ELLIPSIS:
58 re_line += re.escape(re_bucket)
59 re_bucket = ''
60 re_line += '(.*\n)*'
61 else:
62 for char in line:
63 if char == '*':
64 re_line += re.escape(re_bucket)
65 re_bucket = ''
66 re_line += '.*'
67 else: # there can't be any '\*'s in a stack trace
68 re_bucket += char
69 re_line += re.escape(re_bucket)
70 re_bucket = ''
71 re_line += '\n'
72 self._re = re.compile(re_line, re.MULTILINE)
74 def Match(self, report):
75 """Returns bool indicating whether the suppression matches the given report.
77 Args:
78 report: list of strings (function names).
79 Returns:
80 True if the suppression is not empty and matches the report.
81 """
82 if not self._stack:
83 return False
84 if self._re.match('\n'.join(report) + '\n'):
85 return True
86 else:
87 return False
90 class SuppressionError(Exception):
91 def __init__(self, filename, line, report=''):
92 Exception.__init__(self, filename, line, report)
93 self._file = filename
94 self._line = line
95 self._report = report
97 def __str__(self):
98 return 'Error reading suppressions from "%s" (line %d): %s.' % (
99 self._file, self._line, self._report)
102 def ReadSuppressionsFromFile(filename):
103 """Given a file, returns a list of suppressions."""
104 input_file = file(filename, 'r')
105 result = []
106 cur_descr = ''
107 cur_type = ''
108 cur_stack = []
109 nline = 0
110 try:
111 for line in input_file:
112 nline += 1
113 line = line.strip()
114 if line.startswith('#'):
115 continue
116 elif line.startswith('{'):
117 pass
118 elif line.startswith('}'):
119 result.append(Suppression(cur_type, cur_descr, cur_stack))
120 cur_descr = ''
121 cur_type = ''
122 cur_stack = []
123 elif not cur_descr:
124 cur_descr = line
125 continue
126 elif not cur_type:
127 cur_type = line
128 continue
129 elif line.startswith('fun:'):
130 line = line[4:]
131 cur_stack.append(line.strip())
132 elif line.startswith(ELLIPSIS):
133 cur_stack.append(ELLIPSIS)
134 else:
135 raise SuppressionError(filename, nline,
136 '"fun:function_name" or "..." expected')
137 except SuppressionError:
138 input_file.close()
139 raise
140 return result
143 def MatchTest():
144 """Tests the Suppression.Match() capabilities."""
146 def GenSupp(*lines):
147 return Suppression('', '', list(lines))
148 empty = GenSupp()
149 assert not empty.Match([])
150 assert not empty.Match(['foo', 'bar'])
151 asterisk = GenSupp('*bar')
152 assert asterisk.Match(['foobar', 'foobaz'])
153 assert not asterisk.Match(['foobaz', 'foobar'])
154 ellipsis = GenSupp('...', 'foo')
155 assert ellipsis.Match(['foo', 'bar'])
156 assert ellipsis.Match(['bar', 'baz', 'foo'])
157 assert not ellipsis.Match(['bar', 'baz', 'bah'])
158 mixed = GenSupp('...', 'foo*', 'function')
159 assert mixed.Match(['foobar', 'foobaz', 'function'])
160 assert not mixed.Match(['foobar', 'blah', 'function'])
161 at_and_dollar = GenSupp('foo@GLIBC', 'bar@NOCANCEL')
162 assert at_and_dollar.Match(['foo@GLIBC', 'bar@NOCANCEL'])
163 re_chars = GenSupp('.*')
164 assert re_chars.Match(['.foobar'])
165 assert not re_chars.Match(['foobar'])
166 print 'PASS'
169 if __name__ == '__main__':
170 MatchTest()