summaryrefslogtreecommitdiffstats
path: root/tools/heapcheck/suppressions.py
diff options
context:
space:
mode:
authortimurrrr@chromium.org <timurrrr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-01 17:56:01 +0000
committertimurrrr@chromium.org <timurrrr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-01 17:56:01 +0000
commit741e1971f600c76a8ac47a548352578da981cbe0 (patch)
tree25a03e8c307b7b280f994dda4641f10d25b2b0d6 /tools/heapcheck/suppressions.py
parentf2c20fa96403a8db390bc7790b67e1906dad179b (diff)
downloadchromium_src-741e1971f600c76a8ac47a548352578da981cbe0.zip
chromium_src-741e1971f600c76a8ac47a548352578da981cbe0.tar.gz
chromium_src-741e1971f600c76a8ac47a548352578da981cbe0.tar.bz2
Created tools/heapcheck with scripts for running heapchecker-enabled tests.
chrome_tests.sh -- a frontend for the buildbot slave to run the tests under heap leak checker. chrome_tests.py -- almost copied from the similar scripts in ../valgrind/ and ../purify/, invokes heapcheck_test.py for each target. heapcheck_test.py -- runs a single test, processes the logs and applies suppressions to the reports returned by the heap checker. heapcheck_std.sh -- a tiny wrapper for IO redirection. suppressions.py -- provides the support for Valgrind-style stack trace suppressions. This patch was originally prepared by Alexander Potapenko (cc'ed) as http://codereview.chromium.org/400010 TBR=dank,erikkay Review URL: http://codereview.chromium.org/455021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33451 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/heapcheck/suppressions.py')
-rw-r--r--tools/heapcheck/suppressions.py171
1 files changed, 171 insertions, 0 deletions
diff --git a/tools/heapcheck/suppressions.py b/tools/heapcheck/suppressions.py
new file mode 100644
index 0000000..e1b3498
--- /dev/null
+++ b/tools/heapcheck/suppressions.py
@@ -0,0 +1,171 @@
+#!/usr/bin/python
+# Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# suppressions.py
+
+"""Valgrind-style suppressions for heapchecker reports.
+
+Suppressions are defined as follows:
+
+# optional one-line comments anywhere in the suppressions file.
+{
+ Toolname:Errortype
+ Short description of the error.
+ fun:function_name
+ fun:wildcarded_fun*_name
+ # an ellipsis wildcards zero or more functions in a stack.
+ ...
+ fun:some_other_function_name
+}
+
+Note that only a 'fun:' prefix is allowed, i.e. we can't suppress objects and
+source files.
+
+If ran from the command line, suppressions.py does a self-test of the
+Suppression class.
+"""
+
+import re
+
+ELLIPSIS = '...'
+
+
+class Suppression(object):
+ """This class represents a single stack trace suppression.
+
+ Attributes:
+ type: A string representing the error type, e.g. Heapcheck:Leak.
+ description: A string representing the error description.
+ """
+
+ def __init__(self, kind, description, stack):
+ """Inits Suppression.
+
+ stack is a list of function names and/or wildcards.
+
+ Args:
+ kind:
+ description: Same as class attributes.
+ stack: A list of strings.
+ """
+ self.type = kind
+ self.description = description
+ self._stack = stack
+ re_line = ''
+ re_bucket = ''
+ for line in stack:
+ if line == ELLIPSIS:
+ re_line += re.escape(re_bucket)
+ re_bucket = ''
+ re_line += '(.*\n)*'
+ else:
+ for char in line:
+ if char == '*':
+ re_line += re.escape(re_bucket)
+ re_bucket = ''
+ re_line += '.*'
+ else: # there can't be any '\*'s in a stack trace
+ re_bucket += char
+ re_line += re.escape(re_bucket)
+ re_bucket = ''
+ re_line += '\n'
+ self._re = re.compile(re_line, re.MULTILINE)
+
+ def Match(self, report):
+ """Returns bool indicating whether the suppression matches the given report.
+
+ Args:
+ report: list of strings (function names).
+ Returns:
+ True if the suppression is not empty and matches the report.
+ """
+ if not self._stack:
+ return False
+ if self._re.match('\n'.join(report) + '\n'):
+ return True
+ else:
+ return False
+
+
+class SuppressionError(Exception):
+ def __init__(self, filename, line, report=''):
+ Exception.__init__(self, filename, line, report)
+ self._file = filename
+ self._line = line
+ self._report = report
+
+ def __str__(self):
+ return 'Error reading suppressions from "%s" (line %d): %s.' % (
+ self._file, self._line, self._report)
+
+
+def ReadSuppressionsFromFile(filename):
+ """Given a file, returns a list of suppressions."""
+ input_file = file(filename, 'r')
+ result = []
+ cur_descr = ''
+ cur_type = ''
+ cur_stack = []
+ nline = 0
+ try:
+ for line in input_file:
+ nline += 1
+ line = line.strip()
+ if line.startswith('#'):
+ continue
+ elif line.startswith('{'):
+ pass
+ elif line.startswith('}'):
+ result.append(Suppression(cur_type, cur_descr, cur_stack))
+ cur_descr = ''
+ cur_type = ''
+ cur_stack = []
+ elif not cur_type:
+ cur_type = line
+ continue
+ elif not cur_descr:
+ cur_descr = line
+ continue
+ elif line.startswith('fun:'):
+ line = line[4:]
+ cur_stack.append(line.strip())
+ elif line.startswith(ELLIPSIS):
+ cur_stack.append(ELLIPSIS)
+ else:
+ raise SuppressionError(filename, nline,
+ '"fun:function_name" or "..." expected')
+ except SuppressionError:
+ input_file.close()
+ raise
+ return result
+
+
+def MatchTest():
+ """Tests the Suppression.Match() capabilities."""
+
+ def GenSupp(*lines):
+ return Suppression('', '', list(lines))
+ empty = GenSupp()
+ assert not empty.Match([])
+ assert not empty.Match(['foo', 'bar'])
+ asterisk = GenSupp('*bar')
+ assert asterisk.Match(['foobar', 'foobaz'])
+ assert not asterisk.Match(['foobaz', 'foobar'])
+ ellipsis = GenSupp('...', 'foo')
+ assert ellipsis.Match(['foo', 'bar'])
+ assert ellipsis.Match(['bar', 'baz', 'foo'])
+ assert not ellipsis.Match(['bar', 'baz', 'bah'])
+ mixed = GenSupp('...', 'foo*', 'function')
+ assert mixed.Match(['foobar', 'foobaz', 'function'])
+ assert not mixed.Match(['foobar', 'blah', 'function'])
+ at_and_dollar = GenSupp('foo@GLIBC', 'bar@NOCANCEL')
+ assert at_and_dollar.Match(['foo@GLIBC', 'bar@NOCANCEL'])
+ re_chars = GenSupp('.*')
+ assert re_chars.Match(['.foobar'])
+ assert not re_chars.Match(['foobar'])
+ print 'PASS'
+
+if __name__ == '__main__':
+ MatchTest()