diff options
author | timurrrr@chromium.org <timurrrr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-01 17:56:01 +0000 |
---|---|---|
committer | timurrrr@chromium.org <timurrrr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-01 17:56:01 +0000 |
commit | 741e1971f600c76a8ac47a548352578da981cbe0 (patch) | |
tree | 25a03e8c307b7b280f994dda4641f10d25b2b0d6 /tools/heapcheck/suppressions.py | |
parent | f2c20fa96403a8db390bc7790b67e1906dad179b (diff) | |
download | chromium_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.py | 171 |
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() |