summaryrefslogtreecommitdiffstats
path: root/chromium/tools/valgrind/suppressions.py
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/tools/valgrind/suppressions.py')
-rwxr-xr-xchromium/tools/valgrind/suppressions.py1018
1 files changed, 0 insertions, 1018 deletions
diff --git a/chromium/tools/valgrind/suppressions.py b/chromium/tools/valgrind/suppressions.py
deleted file mode 100755
index 48955984d2c..00000000000
--- a/chromium/tools/valgrind/suppressions.py
+++ /dev/null
@@ -1,1018 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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
-
-"""Post-process Valgrind suppression matcher.
-
-Suppressions are defined as follows:
-
-# optional one-line comments anywhere in the suppressions file.
-{
- <Short description of the error>
- Toolname:Errortype
- fun:function_name
- obj:object_filename
- fun:wildcarded_fun*_name
- # an ellipsis wildcards zero or more functions in a stack.
- ...
- fun:some_other_function_name
-}
-
-If ran from the command line, suppressions.py does a self-test
-of the Suppression class.
-"""
-
-import os
-import re
-import sys
-
-sys.path.insert(0, os.path.join(os.path.dirname(__file__),
- '..', 'python', 'google'))
-import path_utils
-
-
-ELLIPSIS = '...'
-
-
-def GetSuppressions():
- suppressions_root = path_utils.ScriptDir()
- JOIN = os.path.join
-
- result = {}
-
- supp_filename = JOIN(suppressions_root, "memcheck", "suppressions.txt")
- vg_common = ReadSuppressionsFromFile(supp_filename)
- supp_filename = JOIN(suppressions_root, "tsan", "suppressions.txt")
- tsan_common = ReadSuppressionsFromFile(supp_filename)
- result['common_suppressions'] = vg_common + tsan_common
-
- supp_filename = JOIN(suppressions_root, "memcheck", "suppressions_linux.txt")
- vg_linux = ReadSuppressionsFromFile(supp_filename)
- supp_filename = JOIN(suppressions_root, "tsan", "suppressions_linux.txt")
- tsan_linux = ReadSuppressionsFromFile(supp_filename)
- result['linux_suppressions'] = vg_linux + tsan_linux
-
- supp_filename = JOIN(suppressions_root, "memcheck", "suppressions_mac.txt")
- vg_mac = ReadSuppressionsFromFile(supp_filename)
- supp_filename = JOIN(suppressions_root, "tsan", "suppressions_mac.txt")
- tsan_mac = ReadSuppressionsFromFile(supp_filename)
- result['mac_suppressions'] = vg_mac + tsan_mac
-
- supp_filename = JOIN(suppressions_root, "tsan", "suppressions_win32.txt")
- tsan_win = ReadSuppressionsFromFile(supp_filename)
- result['win_suppressions'] = tsan_win
-
- supp_filename = JOIN(suppressions_root, "..", "heapcheck", "suppressions.txt")
- result['heapcheck_suppressions'] = ReadSuppressionsFromFile(supp_filename)
-
- supp_filename = JOIN(suppressions_root, "drmemory", "suppressions.txt")
- result['drmem_suppressions'] = ReadSuppressionsFromFile(supp_filename)
- supp_filename = JOIN(suppressions_root, "drmemory", "suppressions_full.txt")
- result['drmem_full_suppressions'] = ReadSuppressionsFromFile(supp_filename)
-
- return result
-
-
-def GlobToRegex(glob_pattern, ignore_case=False):
- """Translate glob wildcards (*?) into regex syntax. Escape the rest."""
- regex = ''
- for char in glob_pattern:
- if char == '*':
- regex += '.*'
- elif char == '?':
- regex += '.'
- elif ignore_case and char.isalpha():
- regex += '[%s%s]' % (char.lower(), char.upper())
- else:
- regex += re.escape(char)
- return ''.join(regex)
-
-
-def StripAndSkipCommentsIterator(lines):
- """Generator of (line_no, line) pairs that strips comments and whitespace."""
- for (line_no, line) in enumerate(lines):
- line = line.strip() # Drop \n
- if line.startswith('#'):
- continue # Comments
- # Skip comment lines, but not empty lines, they indicate the end of a
- # suppression. Add one to the line number as well, since most editors use
- # 1-based numberings, and enumerate is 0-based.
- yield (line_no + 1, line)
-
-
-class Suppression(object):
- """This class represents a single stack trace suppression.
-
- Attributes:
- description: A string representing the error description.
- type: A string representing the error type, e.g. Memcheck:Leak.
- stack: The lines comprising the stack trace for the suppression.
- regex: The actual regex used to match against scraped reports.
- """
-
- def __init__(self, description, type, stack, defined_at, regex):
- """Inits Suppression.
-
- description, type, stack, regex: same as class attributes
- defined_at: file:line identifying where the suppression was defined
- """
- self.description = description
- self.type = type
- self.stack = stack
- self.defined_at = defined_at
- self.regex = re.compile(regex, re.MULTILINE)
-
- def Match(self, suppression_from_report):
- """Returns bool indicating whether this suppression matches
- the suppression generated from Valgrind error report.
-
- We match our suppressions against generated suppressions
- (not against reports) since they have the same format
- while the reports are taken from XML, contain filenames,
- they are demangled, and are generally more difficult to
- parse.
-
- Args:
- suppression_from_report: list of strings (function names).
- Returns:
- True if the suppression is not empty and matches the report.
- """
- if not self.stack:
- return False
- lines = [f.strip() for f in suppression_from_report]
- return self.regex.match('\n'.join(lines) + '\n') is not None
-
-
-def FilenameToTool(filename):
- """Return the name of the tool that a file is related to, or None.
-
- Example mappings:
- tools/heapcheck/suppressions.txt -> heapcheck
- tools/valgrind/tsan/suppressions.txt -> tsan
- tools/valgrind/drmemory/suppressions.txt -> drmemory
- tools/valgrind/drmemory/suppressions_full.txt -> drmemory
- tools/valgrind/memcheck/suppressions.txt -> memcheck
- tools/valgrind/memcheck/suppressions_mac.txt -> memcheck
- """
- filename = os.path.abspath(filename)
- parts = filename.split(os.sep)
- tool = parts[-2]
- if tool in ('heapcheck', 'drmemory', 'memcheck', 'tsan'):
- return tool
- return None
-
-
-def ReadSuppressionsFromFile(filename):
- """Read suppressions from the given file and return them as a list"""
- tool_to_parser = {
- "drmemory": ReadDrMemorySuppressions,
- "memcheck": ReadValgrindStyleSuppressions,
- "tsan": ReadValgrindStyleSuppressions,
- "heapcheck": ReadValgrindStyleSuppressions,
- }
- tool = FilenameToTool(filename)
- assert tool in tool_to_parser, (
- "unknown tool %s for filename %s" % (tool, filename))
- parse_func = tool_to_parser[tool]
-
- # Consider non-existent files to be empty.
- if not os.path.exists(filename):
- return []
-
- input_file = file(filename, 'r')
- try:
- return parse_func(input_file, filename)
- except SuppressionError:
- input_file.close()
- raise
-
-
-class ValgrindStyleSuppression(Suppression):
- """A suppression using the Valgrind syntax.
-
- Most tools, even ones that are not Valgrind-based, use this syntax, ie
- Heapcheck, TSan, etc.
-
- Attributes:
- Same as Suppression.
- """
-
- def __init__(self, description, type, stack, defined_at):
- """Creates a suppression using the Memcheck, TSan, and Heapcheck syntax."""
- regex = '{\n.*\n%s\n' % type
- for line in stack:
- if line == ELLIPSIS:
- regex += '(.*\n)*'
- else:
- regex += GlobToRegex(line)
- regex += '\n'
- regex += '(.*\n)*'
- regex += '}'
-
- # In the recent version of valgrind-variant we've switched
- # from memcheck's default Addr[1248]/Value[1248]/Cond suppression types
- # to simply Unaddressable/Uninitialized.
- # The suppression generator no longer gives us "old" types thus
- # for the "new-type" suppressions:
- # * Memcheck:Unaddressable should also match Addr* reports,
- # * Memcheck:Uninitialized should also match Cond and Value reports,
- #
- # We also want to support legacy suppressions (e.g. copied from
- # upstream bugs etc), so:
- # * Memcheck:Addr[1248] suppressions should match Unaddressable reports,
- # * Memcheck:Cond and Memcheck:Value[1248] should match Uninitialized.
- # Please note the latest two rules only apply to the
- # tools/valgrind/waterfall.sh suppression matcher and the real
- # valgrind-variant Memcheck will not suppress
- # e.g. Addr1 printed as Unaddressable with Addr4 suppression.
- # Be careful to check the access size while copying legacy suppressions!
- for sz in [1, 2, 4, 8]:
- regex = regex.replace("\nMemcheck:Addr%d\n" % sz,
- "\nMemcheck:(Addr%d|Unaddressable)\n" % sz)
- regex = regex.replace("\nMemcheck:Value%d\n" % sz,
- "\nMemcheck:(Value%d|Uninitialized)\n" % sz)
- regex = regex.replace("\nMemcheck:Cond\n",
- "\nMemcheck:(Cond|Uninitialized)\n")
- regex = regex.replace("\nMemcheck:Unaddressable\n",
- "\nMemcheck:(Addr.|Unaddressable)\n")
- regex = regex.replace("\nMemcheck:Uninitialized\n",
- "\nMemcheck:(Cond|Value.|Uninitialized)\n")
-
- return super(ValgrindStyleSuppression, self).__init__(
- description, type, stack, defined_at, regex)
-
- def __str__(self):
- """Stringify."""
- lines = [self.description, self.type] + self.stack
- return "{\n %s\n}\n" % "\n ".join(lines)
-
-
-class SuppressionError(Exception):
- def __init__(self, message, happened_at):
- self._message = message
- self._happened_at = happened_at
-
- def __str__(self):
- return 'Error reading suppressions at %s!\n%s' % (
- self._happened_at, self._message)
-
-
-def ReadValgrindStyleSuppressions(lines, supp_descriptor):
- """Given a list of lines, returns a list of suppressions.
-
- Args:
- lines: a list of lines containing suppressions.
- supp_descriptor: should typically be a filename.
- Used only when printing errors.
- """
- result = []
- cur_descr = ''
- cur_type = ''
- cur_stack = []
- in_suppression = False
- nline = 0
- for line in lines:
- nline += 1
- line = line.strip()
- if line.startswith('#'):
- continue
- if not in_suppression:
- if not line:
- # empty lines between suppressions
- pass
- elif line.startswith('{'):
- in_suppression = True
- pass
- else:
- raise SuppressionError('Expected: "{"',
- "%s:%d" % (supp_descriptor, nline))
- elif line.startswith('}'):
- result.append(
- ValgrindStyleSuppression(cur_descr, cur_type, cur_stack,
- "%s:%d" % (supp_descriptor, nline)))
- cur_descr = ''
- cur_type = ''
- cur_stack = []
- in_suppression = False
- elif not cur_descr:
- cur_descr = line
- continue
- elif not cur_type:
- if (not line.startswith("Memcheck:") and
- not line.startswith("ThreadSanitizer:") and
- (line != "Heapcheck:Leak")):
- raise SuppressionError(
- 'Expected "Memcheck:TYPE", "ThreadSanitizer:TYPE" '
- 'or "Heapcheck:Leak", got "%s"' % line,
- "%s:%d" % (supp_descriptor, nline))
- supp_type = line.split(':')[1]
- if not supp_type in ["Addr1", "Addr2", "Addr4", "Addr8",
- "Cond", "Free", "Jump", "Leak", "Overlap", "Param",
- "Value1", "Value2", "Value4", "Value8",
- "Race", "UnlockNonLocked", "InvalidLock",
- "Unaddressable", "Uninitialized"]:
- raise SuppressionError('Unknown suppression type "%s"' % supp_type,
- "%s:%d" % (supp_descriptor, nline))
- cur_type = line
- continue
- elif re.match("^fun:.*|^obj:.*|^\.\.\.$", line):
- cur_stack.append(line.strip())
- elif len(cur_stack) == 0 and cur_type == "Memcheck:Param":
- cur_stack.append(line.strip())
- else:
- raise SuppressionError(
- '"fun:function_name" or "obj:object_file" or "..." expected',
- "%s:%d" % (supp_descriptor, nline))
- return result
-
-
-def PresubmitCheckSuppressions(supps):
- """Check a list of suppressions and return a list of SuppressionErrors.
-
- Mostly useful for separating the checking logic from the Presubmit API for
- testing.
- """
- known_supp_names = {} # Key: name, Value: suppression.
- errors = []
- for s in supps:
- if re.search("<.*suppression.name.here>", s.description):
- # Suppression name line is
- # <insert_a_suppression_name_here> for Memcheck,
- # <Put your suppression name here> for TSan,
- # name=<insert_a_suppression_name_here> for DrMemory
- errors.append(
- SuppressionError(
- "You've forgotten to put a suppression name like bug_XXX",
- s.defined_at))
- continue
-
- if s.description in known_supp_names:
- errors.append(
- SuppressionError(
- 'Suppression named "%s" is defined more than once, '
- 'see %s' % (s.description,
- known_supp_names[s.description].defined_at),
- s.defined_at))
- else:
- known_supp_names[s.description] = s
- return errors
-
-
-def PresubmitCheck(input_api, output_api):
- """A helper function useful in PRESUBMIT.py
- Returns a list of errors or [].
- """
- sup_regex = re.compile('suppressions.*\.txt$')
- filenames = [f.AbsoluteLocalPath() for f in input_api.AffectedFiles()
- if sup_regex.search(f.LocalPath())]
-
- errors = []
-
- # TODO(timurrrr): warn on putting suppressions into a wrong file,
- # e.g. TSan suppression in a memcheck file.
-
- for f in filenames:
- try:
- supps = ReadSuppressionsFromFile(f)
- errors.extend(PresubmitCheckSuppressions(supps))
- except SuppressionError as e:
- errors.append(e)
-
- return [output_api.PresubmitError(str(e)) for e in errors]
-
-
-class DrMemorySuppression(Suppression):
- """A suppression using the DrMemory syntax.
-
- Attributes:
- instr: The instruction to match.
- Rest inherited from Suppression.
- """
-
- def __init__(self, name, report_type, instr, stack, defined_at):
- """Constructor."""
- self.instr = instr
-
- # Construct the regex.
- regex = '{\n'
- if report_type == 'LEAK':
- regex += '(POSSIBLE )?LEAK'
- else:
- regex += report_type
- regex += '\nname=.*\n'
-
- # TODO(rnk): Implement http://crbug.com/107416#c5 .
- # drmemory_analyze.py doesn't generate suppressions with an instruction in
- # them, so these suppressions will always fail to match. We should override
- # Match to fetch the instruction from the report and try to match against
- # that.
- if instr:
- regex += 'instruction=%s\n' % GlobToRegex(instr)
-
- for line in stack:
- if line == ELLIPSIS:
- regex += '(.*\n)*'
- elif '!' in line:
- (mod, func) = line.split('!')
- if func == ELLIPSIS: # mod!ellipsis frame
- regex += '(%s\!.*\n)+' % GlobToRegex(mod, ignore_case=True)
- else: # mod!func frame
- # Ignore case for the module match, but not the function match.
- regex += '%s\!%s\n' % (GlobToRegex(mod, ignore_case=True),
- GlobToRegex(func, ignore_case=False))
- else:
- regex += GlobToRegex(line)
- regex += '\n'
- regex += '(.*\n)*' # Match anything left in the stack.
- regex += '}'
- return super(DrMemorySuppression, self).__init__(name, report_type, stack,
- defined_at, regex)
-
- def __str__(self):
- """Stringify."""
- text = self.type + "\n"
- if self.description:
- text += "name=%s\n" % self.description
- if self.instr:
- text += "instruction=%s\n" % self.instr
- text += "\n".join(self.stack)
- text += "\n"
- return text
-
-
-# Possible DrMemory error report types. Keep consistent with suppress_name
-# array in drmemory/drmemory/report.c.
-DRMEMORY_ERROR_TYPES = [
- 'UNADDRESSABLE ACCESS',
- 'UNINITIALIZED READ',
- 'INVALID HEAP ARGUMENT',
- 'GDI USAGE ERROR',
- 'HANDLE LEAK',
- 'LEAK',
- 'POSSIBLE LEAK',
- 'WARNING',
- ]
-
-
-# Regexes to match valid drmemory frames.
-DRMEMORY_FRAME_PATTERNS = [
- re.compile(r"^.*\!.*$"), # mod!func
- re.compile(r"^.*!\.\.\.$"), # mod!ellipsis
- re.compile(r"^\<.*\+0x.*\>$"), # <mod+0xoffs>
- re.compile(r"^\<not in a module\>$"),
- re.compile(r"^system call .*$"),
- re.compile(r"^\*$"), # wildcard
- re.compile(r"^\.\.\.$"), # ellipsis
- ]
-
-
-def ReadDrMemorySuppressions(lines, supp_descriptor):
- """Given a list of lines, returns a list of DrMemory suppressions.
-
- Args:
- lines: a list of lines containing suppressions.
- supp_descriptor: should typically be a filename.
- Used only when parsing errors happen.
- """
- lines = StripAndSkipCommentsIterator(lines)
- suppressions = []
- for (line_no, line) in lines:
- if not line:
- continue
- if line not in DRMEMORY_ERROR_TYPES:
- raise SuppressionError('Expected a DrMemory error type, '
- 'found %r instead\n Valid error types: %s' %
- (line, ' '.join(DRMEMORY_ERROR_TYPES)),
- "%s:%d" % (supp_descriptor, line_no))
-
- # Suppression starts here.
- report_type = line
- name = ''
- instr = None
- stack = []
- defined_at = "%s:%d" % (supp_descriptor, line_no)
- found_stack = False
- for (line_no, line) in lines:
- if not found_stack and line.startswith('name='):
- name = line.replace('name=', '')
- elif not found_stack and line.startswith('instruction='):
- instr = line.replace('instruction=', '')
- else:
- # Unrecognized prefix indicates start of stack trace.
- found_stack = True
- if not line:
- # Blank line means end of suppression.
- break
- if not any([regex.match(line) for regex in DRMEMORY_FRAME_PATTERNS]):
- raise SuppressionError(
- ('Unexpected stack frame pattern at line %d\n' +
- 'Frames should be one of the following:\n' +
- ' module!function\n' +
- ' module!...\n' +
- ' <module+0xhexoffset>\n' +
- ' <not in a module>\n' +
- ' system call Name\n' +
- ' *\n' +
- ' ...\n') % line_no, defined_at)
- stack.append(line)
-
- if len(stack) == 0: # In case we hit EOF or blank without any stack frames.
- raise SuppressionError('Suppression "%s" has no stack frames, ends at %d'
- % (name, line_no), defined_at)
- if stack[-1] == ELLIPSIS:
- raise SuppressionError('Suppression "%s" ends in an ellipsis on line %d' %
- (name, line_no), defined_at)
-
- suppressions.append(
- DrMemorySuppression(name, report_type, instr, stack, defined_at))
-
- return suppressions
-
-
-def ParseSuppressionOfType(lines, supp_descriptor, def_line_no, report_type):
- """Parse the suppression starting on this line.
-
- Suppressions start with a type, have an optional name and instruction, and a
- stack trace that ends in a blank line.
- """
-
-
-
-def TestStack(stack, positive, negative, suppression_parser=None):
- """A helper function for SelfTest() that checks a single stack.
-
- Args:
- stack: the stack to match the suppressions.
- positive: the list of suppressions that must match the given stack.
- negative: the list of suppressions that should not match.
- suppression_parser: optional arg for the suppression parser, default is
- ReadValgrindStyleSuppressions.
- """
- if not suppression_parser:
- suppression_parser = ReadValgrindStyleSuppressions
- for supp in positive:
- parsed = suppression_parser(supp.split("\n"), "positive_suppression")
- assert parsed[0].Match(stack.split("\n")), (
- "Suppression:\n%s\ndidn't match stack:\n%s" % (supp, stack))
- for supp in negative:
- parsed = suppression_parser(supp.split("\n"), "negative_suppression")
- assert not parsed[0].Match(stack.split("\n")), (
- "Suppression:\n%s\ndid match stack:\n%s" % (supp, stack))
-
-
-def TestFailPresubmit(supp_text, error_text, suppression_parser=None):
- """A helper function for SelfTest() that verifies a presubmit check fires.
-
- Args:
- supp_text: suppression text to parse.
- error_text: text of the presubmit error we expect to find.
- suppression_parser: optional arg for the suppression parser, default is
- ReadValgrindStyleSuppressions.
- """
- if not suppression_parser:
- suppression_parser = ReadValgrindStyleSuppressions
- try:
- supps = suppression_parser(supp_text.split("\n"), "<presubmit suppression>")
- except SuppressionError, e:
- # If parsing raised an exception, match the error text here.
- assert error_text in str(e), (
- "presubmit text %r not in SuppressionError:\n%r" %
- (error_text, str(e)))
- else:
- # Otherwise, run the presubmit checks over the supps. We expect a single
- # error that has text matching error_text.
- errors = PresubmitCheckSuppressions(supps)
- assert len(errors) == 1, (
- "expected exactly one presubmit error, got:\n%s" % errors)
- assert error_text in str(errors[0]), (
- "presubmit text %r not in SuppressionError:\n%r" %
- (error_text, str(errors[0])))
-
-
-def SelfTest():
- """Tests the Suppression.Match() capabilities."""
-
- test_memcheck_stack_1 = """{
- test
- Memcheck:Leak
- fun:absolutly
- fun:brilliant
- obj:condition
- fun:detection
- fun:expression
- }"""
-
- test_memcheck_stack_2 = """{
- test
- Memcheck:Uninitialized
- fun:absolutly
- fun:brilliant
- obj:condition
- fun:detection
- fun:expression
- }"""
-
- test_memcheck_stack_3 = """{
- test
- Memcheck:Unaddressable
- fun:absolutly
- fun:brilliant
- obj:condition
- fun:detection
- fun:expression
- }"""
-
- test_memcheck_stack_4 = """{
- test
- Memcheck:Addr4
- fun:absolutly
- fun:brilliant
- obj:condition
- fun:detection
- fun:expression
- }"""
-
- test_heapcheck_stack = """{
- test
- Heapcheck:Leak
- fun:absolutly
- fun:brilliant
- obj:condition
- fun:detection
- fun:expression
- }"""
-
- test_tsan_stack = """{
- test
- ThreadSanitizer:Race
- fun:absolutly
- fun:brilliant
- obj:condition
- fun:detection
- fun:expression
- }"""
-
-
- positive_memcheck_suppressions_1 = [
- "{\nzzz\nMemcheck:Leak\nfun:absolutly\n}",
- "{\nzzz\nMemcheck:Leak\nfun:ab*ly\n}",
- "{\nzzz\nMemcheck:Leak\nfun:absolutly\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Leak\n...\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Leak\n...\nfun:detection\n}",
- "{\nzzz\nMemcheck:Leak\nfun:absolutly\n...\nfun:detection\n}",
- "{\nzzz\nMemcheck:Leak\nfun:ab*ly\n...\nfun:detection\n}",
- "{\nzzz\nMemcheck:Leak\n...\nobj:condition\n}",
- "{\nzzz\nMemcheck:Leak\n...\nobj:condition\nfun:detection\n}",
- "{\nzzz\nMemcheck:Leak\n...\nfun:brilliant\nobj:condition\n}",
- ]
-
- positive_memcheck_suppressions_2 = [
- "{\nzzz\nMemcheck:Uninitialized\nfun:absolutly\n}",
- "{\nzzz\nMemcheck:Uninitialized\nfun:ab*ly\n}",
- "{\nzzz\nMemcheck:Uninitialized\nfun:absolutly\nfun:brilliant\n}",
- # Legacy suppression types
- "{\nzzz\nMemcheck:Value1\n...\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Cond\n...\nfun:detection\n}",
- "{\nzzz\nMemcheck:Value8\nfun:absolutly\nfun:brilliant\n}",
- ]
-
- positive_memcheck_suppressions_3 = [
- "{\nzzz\nMemcheck:Unaddressable\nfun:absolutly\n}",
- "{\nzzz\nMemcheck:Unaddressable\nfun:absolutly\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Unaddressable\nfun:absolutly\nfun:brilliant\n}",
- # Legacy suppression types
- "{\nzzz\nMemcheck:Addr1\n...\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Addr8\n...\nfun:detection\n}",
- ]
-
- positive_memcheck_suppressions_4 = [
- "{\nzzz\nMemcheck:Addr4\nfun:absolutly\n}",
- "{\nzzz\nMemcheck:Unaddressable\nfun:absolutly\n}",
- "{\nzzz\nMemcheck:Addr4\nfun:absolutly\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Unaddressable\n...\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Addr4\n...\nfun:detection\n}",
- ]
-
- positive_heapcheck_suppressions = [
- "{\nzzz\nHeapcheck:Leak\n...\nobj:condition\n}",
- "{\nzzz\nHeapcheck:Leak\nfun:absolutly\n}",
- ]
-
- positive_tsan_suppressions = [
- "{\nzzz\nThreadSanitizer:Race\n...\nobj:condition\n}",
- "{\nzzz\nThreadSanitizer:Race\nfun:absolutly\n}",
- ]
-
- negative_memcheck_suppressions_1 = [
- "{\nzzz\nMemcheck:Leak\nfun:abnormal\n}",
- "{\nzzz\nMemcheck:Leak\nfun:ab*liant\n}",
- "{\nzzz\nMemcheck:Leak\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Leak\nobj:condition\n}",
- "{\nzzz\nMemcheck:Addr8\nfun:brilliant\n}",
- ]
-
- negative_memcheck_suppressions_2 = [
- "{\nzzz\nMemcheck:Cond\nfun:abnormal\n}",
- "{\nzzz\nMemcheck:Value2\nfun:abnormal\n}",
- "{\nzzz\nMemcheck:Uninitialized\nfun:ab*liant\n}",
- "{\nzzz\nMemcheck:Value4\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Leak\nobj:condition\n}",
- "{\nzzz\nMemcheck:Addr8\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Unaddressable\nfun:brilliant\n}",
- ]
-
- negative_memcheck_suppressions_3 = [
- "{\nzzz\nMemcheck:Addr1\nfun:abnormal\n}",
- "{\nzzz\nMemcheck:Uninitialized\nfun:absolutly\n}",
- "{\nzzz\nMemcheck:Addr2\nfun:ab*liant\n}",
- "{\nzzz\nMemcheck:Value4\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Leak\nobj:condition\n}",
- "{\nzzz\nMemcheck:Addr8\nfun:brilliant\n}",
- ]
-
- negative_memcheck_suppressions_4 = [
- "{\nzzz\nMemcheck:Addr1\nfun:abnormal\n}",
- "{\nzzz\nMemcheck:Addr4\nfun:abnormal\n}",
- "{\nzzz\nMemcheck:Unaddressable\nfun:abnormal\n}",
- "{\nzzz\nMemcheck:Addr1\nfun:absolutly\n}",
- "{\nzzz\nMemcheck:Addr2\nfun:ab*liant\n}",
- "{\nzzz\nMemcheck:Value4\nfun:brilliant\n}",
- "{\nzzz\nMemcheck:Leak\nobj:condition\n}",
- "{\nzzz\nMemcheck:Addr8\nfun:brilliant\n}",
- ]
-
- negative_heapcheck_suppressions = [
- "{\nzzz\nMemcheck:Leak\nfun:absolutly\n}",
- "{\nzzz\nHeapcheck:Leak\nfun:brilliant\n}",
- ]
-
- negative_tsan_suppressions = [
- "{\nzzz\nThreadSanitizer:Leak\nfun:absolutly\n}",
- "{\nzzz\nThreadSanitizer:Race\nfun:brilliant\n}",
- ]
-
- TestStack(test_memcheck_stack_1,
- positive_memcheck_suppressions_1,
- negative_memcheck_suppressions_1)
- TestStack(test_memcheck_stack_2,
- positive_memcheck_suppressions_2,
- negative_memcheck_suppressions_2)
- TestStack(test_memcheck_stack_3,
- positive_memcheck_suppressions_3,
- negative_memcheck_suppressions_3)
- TestStack(test_memcheck_stack_4,
- positive_memcheck_suppressions_4,
- negative_memcheck_suppressions_4)
- TestStack(test_heapcheck_stack, positive_heapcheck_suppressions,
- negative_heapcheck_suppressions)
- TestStack(test_tsan_stack, positive_tsan_suppressions,
- negative_tsan_suppressions)
-
- # TODO(timurrrr): add TestFailPresubmit tests.
-
- ### DrMemory self tests.
-
- # http://crbug.com/96010 suppression.
- stack_96010 = """{
- UNADDRESSABLE ACCESS
- name=<insert_a_suppression_name_here>
- *!TestingProfile::FinishInit
- *!TestingProfile::TestingProfile
- *!BrowserAboutHandlerTest_WillHandleBrowserAboutURL_Test::TestBody
- *!testing::Test::Run
- }"""
-
- suppress_96010 = [
- "UNADDRESSABLE ACCESS\nname=zzz\n...\n*!testing::Test::Run\n",
- ("UNADDRESSABLE ACCESS\nname=zzz\n...\n" +
- "*!BrowserAboutHandlerTest_WillHandleBrowserAboutURL_Test::TestBody\n"),
- "UNADDRESSABLE ACCESS\nname=zzz\n...\n*!BrowserAboutHandlerTest*\n",
- "UNADDRESSABLE ACCESS\nname=zzz\n*!TestingProfile::FinishInit\n",
- # No name should be needed
- "UNADDRESSABLE ACCESS\n*!TestingProfile::FinishInit\n",
- # Whole trace
- ("UNADDRESSABLE ACCESS\n" +
- "*!TestingProfile::FinishInit\n" +
- "*!TestingProfile::TestingProfile\n" +
- "*!BrowserAboutHandlerTest_WillHandleBrowserAboutURL_Test::TestBody\n" +
- "*!testing::Test::Run\n"),
- ]
-
- negative_96010 = [
- # Wrong type
- "UNINITIALIZED READ\nname=zzz\n*!TestingProfile::FinishInit\n",
- # No ellipsis
- "UNADDRESSABLE ACCESS\nname=zzz\n*!BrowserAboutHandlerTest*\n",
- ]
-
- TestStack(stack_96010, suppress_96010, negative_96010,
- suppression_parser=ReadDrMemorySuppressions)
-
- # Invalid heap arg
- stack_invalid = """{
- INVALID HEAP ARGUMENT
- name=asdf
- *!foo
- }"""
- suppress_invalid = [
- "INVALID HEAP ARGUMENT\n*!foo\n",
- ]
- negative_invalid = [
- "UNADDRESSABLE ACCESS\n*!foo\n",
- ]
-
- TestStack(stack_invalid, suppress_invalid, negative_invalid,
- suppression_parser=ReadDrMemorySuppressions)
-
- # Suppress only ntdll
- stack_in_ntdll = """{
- UNADDRESSABLE ACCESS
- name=<insert_a_suppression_name_here>
- ntdll.dll!RtlTryEnterCriticalSection
- }"""
- stack_not_ntdll = """{
- UNADDRESSABLE ACCESS
- name=<insert_a_suppression_name_here>
- notntdll.dll!RtlTryEnterCriticalSection
- }"""
-
- suppress_in_ntdll = [
- "UNADDRESSABLE ACCESS\nntdll.dll!RtlTryEnterCriticalSection\n",
- ]
- suppress_in_any = [
- "UNADDRESSABLE ACCESS\n*!RtlTryEnterCriticalSection\n",
- ]
-
- TestStack(stack_in_ntdll, suppress_in_ntdll + suppress_in_any, [],
- suppression_parser=ReadDrMemorySuppressions)
- # Make sure we don't wildcard away the "not" part and match ntdll.dll by
- # accident.
- TestStack(stack_not_ntdll, suppress_in_any, suppress_in_ntdll,
- suppression_parser=ReadDrMemorySuppressions)
-
- # Suppress a POSSIBLE LEAK with LEAK.
- stack_foo_possible = """{
- POSSIBLE LEAK
- name=foo possible
- *!foo
- }"""
- suppress_foo_possible = [ "POSSIBLE LEAK\n*!foo\n" ]
- suppress_foo_leak = [ "LEAK\n*!foo\n" ]
- TestStack(stack_foo_possible, suppress_foo_possible + suppress_foo_leak, [],
- suppression_parser=ReadDrMemorySuppressions)
-
- # Don't suppress LEAK with POSSIBLE LEAK.
- stack_foo_leak = """{
- LEAK
- name=foo leak
- *!foo
- }"""
- TestStack(stack_foo_leak, suppress_foo_leak, suppress_foo_possible,
- suppression_parser=ReadDrMemorySuppressions)
-
- # Test case insensitivity of module names.
- stack_user32_mixed_case = """{
- LEAK
- name=<insert>
- USER32.dll!foo
- user32.DLL!bar
- user32.dll!baz
- }"""
- suppress_user32 = [ # Module name case doesn't matter.
- "LEAK\nuser32.dll!foo\nuser32.dll!bar\nuser32.dll!baz\n",
- "LEAK\nUSER32.DLL!foo\nUSER32.DLL!bar\nUSER32.DLL!baz\n",
- ]
- no_suppress_user32 = [ # Function name case matters.
- "LEAK\nuser32.dll!FOO\nuser32.dll!BAR\nuser32.dll!BAZ\n",
- "LEAK\nUSER32.DLL!FOO\nUSER32.DLL!BAR\nUSER32.DLL!BAZ\n",
- ]
- TestStack(stack_user32_mixed_case, suppress_user32, no_suppress_user32,
- suppression_parser=ReadDrMemorySuppressions)
-
- # Test mod!... frames.
- stack_kernel32_through_ntdll = """{
- LEAK
- name=<insert>
- kernel32.dll!foo
- KERNEL32.dll!bar
- kernel32.DLL!baz
- ntdll.dll!quux
- }"""
- suppress_mod_ellipsis = [
- "LEAK\nkernel32.dll!...\nntdll.dll!quux\n",
- "LEAK\nKERNEL32.DLL!...\nntdll.dll!quux\n",
- ]
- no_suppress_mod_ellipsis = [
- # Need one or more matching frames, not zero, unlike regular ellipsis.
- "LEAK\nuser32.dll!...\nkernel32.dll!...\nntdll.dll!quux\n",
- ]
- TestStack(stack_kernel32_through_ntdll, suppress_mod_ellipsis,
- no_suppress_mod_ellipsis,
- suppression_parser=ReadDrMemorySuppressions)
-
- # Test that the presubmit checks work.
- forgot_to_name = """
- UNADDRESSABLE ACCESS
- name=<insert_a_suppression_name_here>
- ntdll.dll!RtlTryEnterCriticalSection
- """
- TestFailPresubmit(forgot_to_name, 'forgotten to put a suppression',
- suppression_parser=ReadDrMemorySuppressions)
-
- named_twice = """
- UNADDRESSABLE ACCESS
- name=http://crbug.com/1234
- *!foo
-
- UNADDRESSABLE ACCESS
- name=http://crbug.com/1234
- *!bar
- """
- TestFailPresubmit(named_twice, 'defined more than once',
- suppression_parser=ReadDrMemorySuppressions)
-
- forgot_stack = """
- UNADDRESSABLE ACCESS
- name=http://crbug.com/1234
- """
- TestFailPresubmit(forgot_stack, 'has no stack frames',
- suppression_parser=ReadDrMemorySuppressions)
-
- ends_in_ellipsis = """
- UNADDRESSABLE ACCESS
- name=http://crbug.com/1234
- ntdll.dll!RtlTryEnterCriticalSection
- ...
- """
- TestFailPresubmit(ends_in_ellipsis, 'ends in an ellipsis',
- suppression_parser=ReadDrMemorySuppressions)
-
- bad_stack_frame = """
- UNADDRESSABLE ACCESS
- name=http://crbug.com/1234
- fun:memcheck_style_frame
- """
- TestFailPresubmit(bad_stack_frame, 'Unexpected stack frame pattern',
- suppression_parser=ReadDrMemorySuppressions)
-
- # Test FilenameToTool.
- filenames_to_tools = {
- "tools/heapcheck/suppressions.txt": "heapcheck",
- "tools/valgrind/tsan/suppressions.txt": "tsan",
- "tools/valgrind/drmemory/suppressions.txt": "drmemory",
- "tools/valgrind/drmemory/suppressions_full.txt": "drmemory",
- "tools/valgrind/memcheck/suppressions.txt": "memcheck",
- "tools/valgrind/memcheck/suppressions_mac.txt": "memcheck",
- "asdf/tools/valgrind/memcheck/suppressions_mac.txt": "memcheck",
- "foo/bar/baz/tools/valgrind/memcheck/suppressions_mac.txt": "memcheck",
- "foo/bar/baz/tools/valgrind/suppressions.txt": None,
- "tools/valgrind/suppressions.txt": None,
- }
- for (filename, expected_tool) in filenames_to_tools.items():
- filename.replace('/', os.sep) # Make the path look native.
- tool = FilenameToTool(filename)
- assert tool == expected_tool, (
- "failed to get expected tool for filename %r, expected %s, got %s" %
- (filename, expected_tool, tool))
-
- # Test ValgrindStyleSuppression.__str__.
- supp = ValgrindStyleSuppression("http://crbug.com/1234", "Memcheck:Leak",
- ["...", "fun:foo"], "supp.txt:1")
- # Intentional 3-space indent. =/
- supp_str = ("{\n"
- " http://crbug.com/1234\n"
- " Memcheck:Leak\n"
- " ...\n"
- " fun:foo\n"
- "}\n")
- assert str(supp) == supp_str, (
- "str(supp) != supp_str:\nleft: %s\nright: %s" % (str(supp), supp_str))
-
- # Test DrMemorySuppression.__str__.
- supp = DrMemorySuppression(
- "http://crbug.com/1234", "LEAK", None, ["...", "*!foo"], "supp.txt:1")
- supp_str = ("LEAK\n"
- "name=http://crbug.com/1234\n"
- "...\n"
- "*!foo\n")
- assert str(supp) == supp_str, (
- "str(supp) != supp_str:\nleft: %s\nright: %s" % (str(supp), supp_str))
-
- supp = DrMemorySuppression(
- "http://crbug.com/1234", "UNINITIALIZED READ", "test 0x08(%eax) $0x01",
- ["ntdll.dll!*", "*!foo"], "supp.txt:1")
- supp_str = ("UNINITIALIZED READ\n"
- "name=http://crbug.com/1234\n"
- "instruction=test 0x08(%eax) $0x01\n"
- "ntdll.dll!*\n"
- "*!foo\n")
- assert str(supp) == supp_str, (
- "str(supp) != supp_str:\nleft: %s\nright: %s" % (str(supp), supp_str))
-
-
-if __name__ == '__main__':
- SelfTest()
- print 'PASS'