summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/valgrind/README6
-rwxr-xr-xtools/valgrind/chrome_tests.py2
-rwxr-xr-xtools/valgrind/chrome_tests.sh34
-rwxr-xr-xtools/valgrind/suppressions.py60
-rw-r--r--tools/valgrind/tsan/README5
-rwxr-xr-xtools/valgrind/tsan_analyze.py271
-rwxr-xr-xtools/valgrind/valgrind.sh8
-rw-r--r--tools/valgrind/valgrind_test.py371
8 files changed, 22 insertions, 735 deletions
diff --git a/tools/valgrind/README b/tools/valgrind/README
index ad26439..68f793f 100644
--- a/tools/valgrind/README
+++ b/tools/valgrind/README
@@ -2,3 +2,9 @@ Historically this directory has been a home for Valgrind and ThreadSanitizer.
Since then other memory tools used in Chromium started squatting here and the
name became confusing.
We're replacing tools/valgrind with tools/memory/ new tools should go there.
+
+Attention: ThreadSanitizer v1 has been retired and files in this dir
+should not be used anymore. Please refer to
+http://dev.chromium.org/developers/testing/threadsanitizer-tsan-v2
+for the instructions on using ThreadSanitizer v2.
+Namely, the suppressions now reside in base/debug/tsan_suppressions.cc
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index e43c605..eef3175 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -33,7 +33,7 @@ class ExecutableNotFound(Exception): pass
class BadBinary(Exception): pass
class ChromeTests:
- SLOW_TOOLS = ["memcheck", "tsan", "tsan_rv", "drmemory"]
+ SLOW_TOOLS = ["memcheck", "drmemory"]
LAYOUT_TESTS_DEFAULT_CHUNK_SIZE = 300
def __init__(self, options, args, test):
diff --git a/tools/valgrind/chrome_tests.sh b/tools/valgrind/chrome_tests.sh
index df5e8e7..479138e 100755
--- a/tools/valgrind/chrome_tests.sh
+++ b/tools/valgrind/chrome_tests.sh
@@ -9,11 +9,10 @@
export THISDIR=`dirname $0`
ARGV_COPY="$@"
-# We need to set CHROME_VALGRIND iff using Memcheck or TSan-Valgrind:
+# We need to set CHROME_VALGRIND iff using Memcheck:
# tools/valgrind/chrome_tests.sh --tool memcheck
# or
# tools/valgrind/chrome_tests.sh --tool=memcheck
-# (same for "--tool=tsan")
tool="memcheck" # Default to memcheck.
while (( "$#" ))
do
@@ -35,14 +34,6 @@ case "$tool" in
"memcheck")
NEEDS_VALGRIND=1
;;
- "tsan" | "tsan_rv")
- if [ "`uname -s`" == CYGWIN* ]
- then
- NEEDS_PIN=1
- else
- NEEDS_VALGRIND=1
- fi
- ;;
"drmemory" | "drmemory_light" | "drmemory_full" | "drmemory_pattern")
NEEDS_DRMEMORY=1
;;
@@ -95,28 +86,5 @@ then
fi
fi
-if [ "$NEEDS_PIN" == "1" ]
-then
- if [ -z "$PIN_COMMAND" ]
- then
- # Set up PIN_COMMAND to invoke TSan.
- TSAN_PATH="$THISDIR/../../third_party/tsan"
- TSAN_SFX="$TSAN_PATH/tsan-x86-windows-sfx.exe"
- echo "$TSAN_SFX"
- if [ ! -f $TSAN_SFX ]
- then
- echo "Can't find ThreadSanitizer executables."
- echo "See http://www.chromium.org/developers/how-tos/using-valgrind/threadsanitizer/threadsanitizer-on-windows"
- echo "for the instructions on how to get them."
- exit 1
- fi
-
- chmod +x "$TSAN_SFX" # Cygwin won't run it without +x.
- "$TSAN_SFX" -o"$TSAN_PATH"/unpacked -y
- export PIN_COMMAND="$TSAN_PATH/unpacked/tsan-x86-windows/tsan.bat"
- fi
-fi
-
-
PYTHONPATH=$THISDIR/../python/google python \
"$THISDIR/chrome_tests.py" $ARGV_COPY
diff --git a/tools/valgrind/suppressions.py b/tools/valgrind/suppressions.py
index c655e12..e066bed 100755
--- a/tools/valgrind/suppressions.py
+++ b/tools/valgrind/suppressions.py
@@ -45,25 +45,15 @@ def GetSuppressions():
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
+ result['common_suppressions'] = vg_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
+ result['linux_suppressions'] = vg_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
+ result['mac_suppressions'] = vg_mac
supp_filename = JOIN(suppressions_root, "drmemory", "suppressions.txt")
result['drmem_suppressions'] = ReadSuppressionsFromFile(supp_filename)
@@ -147,7 +137,6 @@ def FilenameToTool(filename):
"""Return the name of the tool that a file is related to, or None.
Example mappings:
- 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
@@ -156,7 +145,7 @@ def FilenameToTool(filename):
filename = os.path.abspath(filename)
parts = filename.split(os.sep)
tool = parts[-2]
- if tool in ('drmemory', 'memcheck', 'tsan'):
+ if tool in ('drmemory', 'memcheck'):
return tool
return None
@@ -166,7 +155,6 @@ def ReadSuppressionsFromFile(filename):
tool_to_parser = {
"drmemory": ReadDrMemorySuppressions,
"memcheck": ReadValgrindStyleSuppressions,
- "tsan": ReadValgrindStyleSuppressions,
}
tool = FilenameToTool(filename)
assert tool in tool_to_parser, (
@@ -188,15 +176,14 @@ def ReadSuppressionsFromFile(filename):
class ValgrindStyleSuppression(Suppression):
"""A suppression using the Valgrind syntax.
- Most tools, even ones that are not Valgrind-based, use this syntax, ie
- TSan, etc.
+ Most tools, even ones that are not Valgrind-based, use this syntax.
Attributes:
Same as Suppression.
"""
def __init__(self, description, type, stack, defined_at):
- """Creates a suppression using the Memcheck and TSan, syntax."""
+ """Creates a suppression using the Memcheck syntax."""
regex = '{\n.*\n%s\n' % type
for line in stack:
if line == ELLIPSIS:
@@ -296,17 +283,14 @@ def ReadValgrindStyleSuppressions(lines, supp_descriptor):
cur_descr = line
continue
elif not cur_type:
- if (not line.startswith("Memcheck:") and
- not line.startswith("ThreadSanitizer:")):
+ if not line.startswith("Memcheck:"):
raise SuppressionError(
- 'Expected "Memcheck:TYPE" or "ThreadSanitizer:TYPE", '
- 'got "%s"' % line,
+ 'Expected "Memcheck:TYPE", 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))
@@ -335,7 +319,6 @@ def PresubmitCheckSuppressions(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(
@@ -365,9 +348,6 @@ def PresubmitCheck(input_api, output_api):
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)
@@ -629,17 +609,6 @@ def SelfTest():
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}",
@@ -680,11 +649,6 @@ def SelfTest():
"{\nzzz\nMemcheck:Addr4\n...\nfun:detection\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}",
@@ -723,11 +687,6 @@ def SelfTest():
"{\nzzz\nMemcheck:Addr8\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)
@@ -740,8 +699,6 @@ def SelfTest():
TestStack(test_memcheck_stack_4,
positive_memcheck_suppressions_4,
negative_memcheck_suppressions_4)
- TestStack(test_tsan_stack, positive_tsan_suppressions,
- negative_tsan_suppressions)
# TODO(timurrrr): add TestFailPresubmit tests.
@@ -932,7 +889,6 @@ def SelfTest():
# Test FilenameToTool.
filenames_to_tools = {
- "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",
diff --git a/tools/valgrind/tsan/README b/tools/valgrind/tsan/README
deleted file mode 100644
index 132b5c6..0000000
--- a/tools/valgrind/tsan/README
+++ /dev/null
@@ -1,5 +0,0 @@
-Attention: ThreadSanitizer v1 has been retired and files in this dir
-should not be used anymore. Please refer to
-http://dev.chromium.org/developers/testing/threadsanitizer-tsan-v2
-for the instructions on using ThreadSanitizer v2.
-Namely, the suppressions now reside in base/debug/tsan_suppressions.cc
diff --git a/tools/valgrind/tsan_analyze.py b/tools/valgrind/tsan_analyze.py
deleted file mode 100755
index 2c744e2..0000000
--- a/tools/valgrind/tsan_analyze.py
+++ /dev/null
@@ -1,271 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-# tsan_analyze.py
-
-''' Given a ThreadSanitizer output file, parses errors and uniques them.'''
-
-import gdb_helper
-
-from collections import defaultdict
-import hashlib
-import logging
-import optparse
-import os
-import re
-import subprocess
-import sys
-import time
-
-import common
-
-# Global symbol table (ugh)
-TheAddressTable = None
-
-class _StackTraceLine(object):
- def __init__(self, line, address, binary):
- self.raw_line_ = line
- self.address = address
- self.binary = binary
- def __str__(self):
- global TheAddressTable
- file, line = TheAddressTable.GetFileLine(self.binary, self.address)
- if (file is None) or (line is None):
- return self.raw_line_
- else:
- return self.raw_line_.replace(self.binary, '%s:%s' % (file, line))
-
-class TsanAnalyzer(object):
- ''' Given a set of ThreadSanitizer output files, parse all the errors out of
- them, unique them and output the results.'''
-
- LOAD_LIB_RE = re.compile('--[0-9]+-- ([^(:]*) \((0x[0-9a-f]+)\)')
- TSAN_LINE_RE = re.compile('==[0-9]+==\s*[#0-9]+\s*'
- '([0-9A-Fa-fx]+):'
- '(?:[^ ]* )*'
- '([^ :\n]+)'
- '')
- THREAD_CREATION_STR = ("INFO: T.* "
- "(has been created by T.* at this point|is program's main thread)")
-
- SANITY_TEST_SUPPRESSION = ("ThreadSanitizer sanity test "
- "(ToolsSanityTest.DataRace)")
- TSAN_RACE_DESCRIPTION = "Possible data race"
- TSAN_WARNING_DESCRIPTION = ("Unlocking a non-locked lock"
- "|accessing an invalid lock"
- "|which did not acquire this lock")
- RACE_VERIFIER_LINE = "Confirmed a race|unexpected race"
- TSAN_ASSERTION = "Assertion failed: "
-
- def __init__(self, use_gdb=False):
- '''Reads in a set of files.'''
-
- self._use_gdb = use_gdb
- self._cur_testcase = None
-
- def ReadLine(self):
- self.line_ = self.cur_fd_.readline()
- self.stack_trace_line_ = None
- if not self._use_gdb:
- return
- global TheAddressTable
- match = TsanAnalyzer.LOAD_LIB_RE.match(self.line_)
- if match:
- binary, ip = match.groups()
- TheAddressTable.AddBinaryAt(binary, ip)
- return
- match = TsanAnalyzer.TSAN_LINE_RE.match(self.line_)
- if match:
- address, binary_name = match.groups()
- stack_trace_line = _StackTraceLine(self.line_, address, binary_name)
- TheAddressTable.Add(stack_trace_line.binary, stack_trace_line.address)
- self.stack_trace_line_ = stack_trace_line
-
- def ReadSection(self):
- """ Example of a section:
- ==4528== WARNING: Possible data race: {{{
- ==4528== T20 (L{}):
- ==4528== #0 MyTest::Foo1
- ==4528== #1 MyThread::ThreadBody
- ==4528== Concurrent write happened at this point:
- ==4528== T19 (L{}):
- ==4528== #0 MyTest::Foo2
- ==4528== #1 MyThread::ThreadBody
- ==4528== }}}
- ------- suppression -------
- {
- <Put your suppression name here>
- ThreadSanitizer:Race
- fun:MyTest::Foo1
- fun:MyThread::ThreadBody
- }
- ------- end suppression -------
- """
- result = [self.line_]
- if re.search("{{{", self.line_):
- while not re.search('}}}', self.line_):
- self.ReadLine()
- if self.stack_trace_line_ is None:
- result.append(self.line_)
- else:
- result.append(self.stack_trace_line_)
- self.ReadLine()
- if re.match('-+ suppression -+', self.line_):
- # We need to calculate the suppression hash and prepend a line like
- # "Suppression (error hash=#0123456789ABCDEF#):" so the buildbot can
- # extract the suppression snippet.
- supp = ""
- while not re.match('-+ end suppression -+', self.line_):
- self.ReadLine()
- supp += self.line_
- self.ReadLine()
- if self._cur_testcase:
- result.append("The report came from the `%s` test.\n" % \
- self._cur_testcase)
- result.append("Suppression (error hash=#%016X#):\n" % \
- (int(hashlib.md5(supp).hexdigest()[:16], 16)))
- result.append(" For more info on using suppressions see "
- "http://dev.chromium.org/developers/how-tos/using-valgrind/threadsanitizer#TOC-Suppressing-data-races\n")
- result.append(supp)
- else:
- self.ReadLine()
-
- return result
-
- def ReadTillTheEnd(self):
- result = [self.line_]
- while self.line_:
- self.ReadLine()
- result.append(self.line_)
- return result
-
- def ParseReportFile(self, filename):
- '''Parses a report file and returns a list of ThreadSanitizer reports.
-
-
- Args:
- filename: report filename.
- Returns:
- list of (list of (str iff self._use_gdb, _StackTraceLine otherwise)).
- '''
- ret = []
- self.cur_fd_ = open(filename, 'r')
-
- while True:
- # Read ThreadSanitizer reports.
- self.ReadLine()
- if not self.line_:
- break
-
- while True:
- tmp = []
- while re.search(TsanAnalyzer.RACE_VERIFIER_LINE, self.line_):
- tmp.append(self.line_)
- self.ReadLine()
- while re.search(TsanAnalyzer.THREAD_CREATION_STR, self.line_):
- tmp.extend(self.ReadSection())
- if re.search(TsanAnalyzer.TSAN_RACE_DESCRIPTION, self.line_):
- tmp.extend(self.ReadSection())
- ret.append(tmp) # includes RaceVerifier and thread creation stacks
- elif (re.search(TsanAnalyzer.TSAN_WARNING_DESCRIPTION, self.line_) and
- not common.IsWindows()): # workaround for http://crbug.com/53198
- tmp.extend(self.ReadSection())
- ret.append(tmp)
- else:
- break
-
- tmp = []
- if re.search(TsanAnalyzer.TSAN_ASSERTION, self.line_):
- tmp.extend(self.ReadTillTheEnd())
- ret.append(tmp)
- break
-
- match = re.search("used_suppression:\s+([0-9]+)\s(.*)", self.line_)
- if match:
- count, supp_name = match.groups()
- count = int(count)
- self.used_suppressions[supp_name] += count
- self.cur_fd_.close()
- return ret
-
- def GetReports(self, files):
- '''Extracts reports from a set of files.
-
- Reads a set of files and returns a list of all discovered
- ThreadSanitizer race reports. As a side effect, populates
- self.used_suppressions with appropriate info.
- '''
-
- global TheAddressTable
- if self._use_gdb:
- TheAddressTable = gdb_helper.AddressTable()
- else:
- TheAddressTable = None
- reports = []
- self.used_suppressions = defaultdict(int)
- for file in files:
- reports.extend(self.ParseReportFile(file))
- if self._use_gdb:
- TheAddressTable.ResolveAll()
- # Make each line of each report a string.
- reports = map(lambda(x): map(str, x), reports)
- return [''.join(report_lines) for report_lines in reports]
-
- def Report(self, files, testcase, check_sanity=False):
- '''Reads in a set of files and prints ThreadSanitizer report.
-
- Args:
- files: A list of filenames.
- check_sanity: if true, search for SANITY_TEST_SUPPRESSIONS
- '''
-
- # We set up _cur_testcase class-wide variable to avoid passing it through
- # about 5 functions.
- self._cur_testcase = testcase
- reports = self.GetReports(files)
- self._cur_testcase = None # just in case, shouldn't be used anymore
-
- common.PrintUsedSuppressionsList(self.used_suppressions)
-
-
- retcode = 0
- if reports:
- sys.stdout.flush()
- sys.stderr.flush()
- logging.info("FAIL! Found %i report(s)" % len(reports))
- for report in reports:
- logging.info('\n' + report)
- sys.stdout.flush()
- retcode = -1
-
- # Report tool's insanity even if there were errors.
- if (check_sanity and
- TsanAnalyzer.SANITY_TEST_SUPPRESSION not in self.used_suppressions):
- logging.error("FAIL! Sanity check failed!")
- retcode = -3
-
- if retcode != 0:
- return retcode
-
- logging.info("PASS: No reports found")
- return 0
-
-
-def main():
- '''For testing only. The TsanAnalyzer class should be imported instead.'''
- parser = optparse.OptionParser("usage: %prog <files to analyze>")
-
- (options, args) = parser.parse_args()
- if not args:
- parser.error("no filename specified")
- filenames = args
-
- logging.getLogger().setLevel(logging.INFO)
- analyzer = TsanAnalyzer(use_gdb=True)
- return analyzer.Report(filenames, None)
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/tools/valgrind/valgrind.sh b/tools/valgrind/valgrind.sh
index 52f634a..59b4071 100755
--- a/tools/valgrind/valgrind.sh
+++ b/tools/valgrind/valgrind.sh
@@ -29,13 +29,6 @@ setup_memcheck() {
"--num-callers=30")
}
-setup_tsan() {
- RUN_COMMAND="valgrind-tsan.sh"
- IGNORE_FILE="$THISDIR/tsan/ignores.txt"
- DEFAULT_TOOL_FLAGS=("--announce-threads" "--pure-happens-before=yes" \
- "--ignore=$IGNORE_FILE")
-}
-
setup_unknown() {
echo "Unknown tool \"$TOOL_NAME\" specified, the result is not guaranteed"
DEFAULT_TOOL_FLAGS=()
@@ -65,7 +58,6 @@ fi
case $TOOL_NAME in
memcheck*) setup_memcheck "$1";;
- tsan*) setup_tsan;;
*) setup_unknown;;
esac
diff --git a/tools/valgrind/valgrind_test.py b/tools/valgrind/valgrind_test.py
index 24fa32ac..5576ed3 100644
--- a/tools/valgrind/valgrind_test.py
+++ b/tools/valgrind/valgrind_test.py
@@ -22,11 +22,9 @@ import common
import drmemory_analyze
import memcheck_analyze
-import tsan_analyze
class BaseTool(object):
- """Abstract class for running Valgrind-, PIN-based and other dynamic
- error detector tools.
+ """Abstract class for running dynamic error detection tools.
Always subclass this and implement ToolCommand with framework- and
tool-specific stuff.
@@ -107,7 +105,7 @@ class BaseTool(object):
# To add framework- or tool-specific flags, please add a hook using
# RegisterOptionParserHook in the corresponding subclass.
- # See ValgrindTool and ThreadSanitizerBase for examples.
+ # See ValgrindTool for an example.
for hook in self.option_parser_hooks:
hook(self, self._parser)
@@ -229,10 +227,6 @@ class BaseTool(object):
def Run(self, args, module, min_runtime_in_seconds=0):
MODULES_TO_SANITY_CHECK = ["base"]
- # TODO(timurrrr): this is a temporary workaround for http://crbug.com/47844
- if self.ToolName() == "tsan" and common.IsMac():
- MODULES_TO_SANITY_CHECK = []
-
check_sanity = module in MODULES_TO_SANITY_CHECK
return self.Main(args, check_sanity, min_runtime_in_seconds)
@@ -251,11 +245,6 @@ class ValgrindTool(BaseTool):
# Override if tool prefers nonxml output
return True
- def SelfContained(self):
- # Returns true iff the tool is distibuted as a self-contained
- # .sh script (e.g. ThreadSanitizer)
- return False
-
def ExtendOptionParser(self, parser):
parser.add_option("", "--suppressions", default=[],
action="append",
@@ -354,14 +343,11 @@ class ValgrindTool(BaseTool):
tool_name = self.ToolName()
# Construct the valgrind command.
- if self.SelfContained():
- proc = ["valgrind-%s.sh" % tool_name]
+ if 'CHROME_VALGRIND' in os.environ:
+ path = os.path.join(os.environ['CHROME_VALGRIND'], "bin", "valgrind")
else:
- if 'CHROME_VALGRIND' in os.environ:
- path = os.path.join(os.environ['CHROME_VALGRIND'], "bin", "valgrind")
- else:
- path = "valgrind"
- proc = [path, "--tool=%s" % tool_name]
+ path = "valgrind"
+ proc = [path, "--tool=%s" % tool_name]
proc += ["--num-callers=%i" % int(self._options.num_callers)]
@@ -583,212 +569,6 @@ class Memcheck(ValgrindTool):
return ret
-class PinTool(BaseTool):
- """Abstract class for running PIN tools.
-
- Always subclass this and implement ToolSpecificFlags() and
- ExtendOptionParser() for tool-specific stuff.
- """
- def PrepareForTest(self):
- pass
-
- def ToolSpecificFlags(self):
- raise NotImplementedError, "This method should be implemented " \
- "in the tool-specific subclass"
-
- def ToolCommand(self):
- """Get the PIN command to run."""
-
- # Construct the PIN command.
- pin_cmd = os.getenv("PIN_COMMAND")
- if not pin_cmd:
- raise RuntimeError, "Please set PIN_COMMAND environment variable " \
- "with the path to pin.exe"
- proc = pin_cmd.split(" ")
-
- proc += self.ToolSpecificFlags()
-
- # The PIN command is constructed.
-
- # PIN requires -- to separate PIN flags from the executable name.
- # self._args begins with the exe to be run.
- proc += ["--"]
-
- proc += self._args
- return proc
-
-
-class ThreadSanitizerBase(object):
- """ThreadSanitizer
- Dynamic data race detector for Linux, Mac and Windows.
-
- http://code.google.com/p/data-race-test/wiki/ThreadSanitizer
-
- Since TSan works on both Valgrind (Linux, Mac) and PIN (Windows), we need
- to have multiple inheritance
- """
-
- INFO_MESSAGE="Please see http://dev.chromium.org/developers/how-tos/" \
- "using-valgrind/threadsanitizer for the info on " \
- "ThreadSanitizer"
-
- def __init__(self):
- super(ThreadSanitizerBase, self).__init__()
- self.RegisterOptionParserHook(ThreadSanitizerBase.ExtendOptionParser)
-
- def ToolName(self):
- return "tsan"
-
- def UseXML(self):
- return False
-
- def SelfContained(self):
- return True
-
- def ExtendOptionParser(self, parser):
- parser.add_option("", "--hybrid", default="no",
- dest="hybrid",
- help="Finds more data races, may give false positive "
- "reports unless the code is annotated")
- parser.add_option("", "--announce-threads", default="yes",
- dest="announce_threads",
- help="Show the the stack traces of thread creation")
- parser.add_option("", "--free-is-write", default="no",
- dest="free_is_write",
- help="Treat free()/operator delete as memory write. "
- "This helps finding more data races, but (currently) "
- "this may give false positive reports on std::string "
- "internals, see http://code.google.com/p/data-race-test"
- "/issues/detail?id=40")
-
- def EvalBoolFlag(self, flag_value):
- if (flag_value in ["1", "true", "yes"]):
- return True
- elif (flag_value in ["0", "false", "no"]):
- return False
- raise RuntimeError, "Can't parse flag value (%s)" % flag_value
-
- def ToolSpecificFlags(self):
- ret = []
-
- ignore_files = ["ignores.txt"]
- for platform_suffix in common.PlatformNames():
- ignore_files.append("ignores_%s.txt" % platform_suffix)
- for ignore_file in ignore_files:
- fullname = os.path.join(self._source_dir,
- "tools", "valgrind", "tsan", ignore_file)
- if os.path.exists(fullname):
- fullname = common.NormalizeWindowsPath(fullname)
- ret += ["--ignore=%s" % fullname]
-
- # This should shorten filepaths for local builds.
- ret += ["--file-prefix-to-cut=%s/" % self._source_dir]
-
- # This should shorten filepaths on bots.
- ret += ["--file-prefix-to-cut=build/src/"]
- ret += ["--file-prefix-to-cut=out/Release/../../"]
-
- # This should shorten filepaths for functions intercepted in TSan.
- ret += ["--file-prefix-to-cut=scripts/tsan/tsan/"]
- ret += ["--file-prefix-to-cut=src/tsan/tsan/"]
-
- ret += ["--gen-suppressions=true"]
-
- if self.EvalBoolFlag(self._options.hybrid):
- ret += ["--hybrid=yes"] # "no" is the default value for TSAN
-
- if self.EvalBoolFlag(self._options.announce_threads):
- ret += ["--announce-threads"]
-
- if self.EvalBoolFlag(self._options.free_is_write):
- ret += ["--free-is-write=yes"]
- else:
- ret += ["--free-is-write=no"]
-
-
- # --show-pc flag is needed for parsing the error logs on Darwin.
- if platform_suffix == 'mac':
- ret += ["--show-pc=yes"]
- ret += ["--show-pid=no"]
-
- boring_callers = common.BoringCallers(mangled=False, use_re_wildcards=False)
- # TODO(timurrrr): In fact, we want "starting from .." instead of "below .."
- for bc in boring_callers:
- ret += ["--cut_stack_below=%s" % bc]
-
- return ret
-
-
-class ThreadSanitizerPosix(ThreadSanitizerBase, ValgrindTool):
- def ToolSpecificFlags(self):
- proc = ThreadSanitizerBase.ToolSpecificFlags(self)
- # The -v flag is needed for printing the list of used suppressions and
- # obtaining addresses for loaded shared libraries on Mac.
- proc += ["-v"]
- return proc
-
- def CreateAnalyzer(self):
- use_gdb = common.IsMac()
- return tsan_analyze.TsanAnalyzer(use_gdb)
-
- def Analyze(self, check_sanity=False):
- ret = self.GetAnalyzeResults(check_sanity)
-
- if ret != 0:
- logging.info(self.INFO_MESSAGE)
- return ret
-
-
-class ThreadSanitizerWindows(ThreadSanitizerBase, PinTool):
-
- def __init__(self):
- super(ThreadSanitizerWindows, self).__init__()
- self.RegisterOptionParserHook(ThreadSanitizerWindows.ExtendOptionParser)
-
- def ExtendOptionParser(self, parser):
- parser.add_option("", "--suppressions", default=[],
- action="append",
- help="path to TSan suppression file")
-
-
- def ToolSpecificFlags(self):
- add_env = {
- "CHROME_ALLOCATOR" : "WINHEAP",
- }
- for k,v in add_env.iteritems():
- logging.info("export %s=%s", k, v)
- os.putenv(k, v)
-
- proc = ThreadSanitizerBase.ToolSpecificFlags(self)
- # On PIN, ThreadSanitizer has its own suppression mechanism
- # and --log-file flag which work exactly on Valgrind.
- suppression_count = 0
- for suppression_file in self._options.suppressions:
- if os.path.exists(suppression_file):
- suppression_count += 1
- suppression_file = common.NormalizeWindowsPath(suppression_file)
- proc += ["--suppressions=%s" % suppression_file]
-
- if not suppression_count:
- logging.warning("WARNING: NOT USING SUPPRESSIONS!")
-
- logfilename = self.log_dir + "/tsan.%p"
- proc += ["--log-file=" + common.NormalizeWindowsPath(logfilename)]
-
- # TODO(timurrrr): Add flags for Valgrind trace children analog when we
- # start running complex tests (e.g. UI) under TSan/Win.
-
- return proc
-
- def Analyze(self, check_sanity=False):
- filenames = glob.glob(self.log_dir + "/tsan.*")
- analyzer = tsan_analyze.TsanAnalyzer()
- ret = analyzer.Report(filenames, None, check_sanity)
- if ret != 0:
- logging.info(self.INFO_MESSAGE)
- return ret
-
-
class DrMemory(BaseTool):
"""Dr.Memory
Dynamic memory error detector for Windows.
@@ -963,7 +743,6 @@ class DrMemory(BaseTool):
proc += ["--"]
if self._options.indirect or self._options.indirect_webkit_layout:
- # TODO(timurrrr): reuse for TSan on Windows
wrapper_path = os.path.join(self._source_dir,
"tools", "valgrind", "browser_wrapper_win.py")
wrapper = " ".join(["python", wrapper_path] + proc)
@@ -1034,146 +813,10 @@ class DrMemory(BaseTool):
return ret
-# RaceVerifier support. See
-# http://code.google.com/p/data-race-test/wiki/RaceVerifier for more details.
-class ThreadSanitizerRV1Analyzer(tsan_analyze.TsanAnalyzer):
- """ TsanAnalyzer that saves race reports to a file. """
-
- TMP_FILE = "rvlog.tmp"
-
- def __init__(self, source_dir, use_gdb):
- super(ThreadSanitizerRV1Analyzer, self).__init__(use_gdb)
- self.out = open(self.TMP_FILE, "w")
-
- def Report(self, files, testcase, check_sanity=False):
- reports = self.GetReports(files)
- for report in reports:
- print >>self.out, report
- if len(reports) > 0:
- logging.info("RaceVerifier pass 1 of 2, found %i reports" % len(reports))
- return -1
- return 0
-
- def CloseOutputFile(self):
- self.out.close()
-
-
-class ThreadSanitizerRV1Mixin(object):
- """RaceVerifier first pass.
-
- Runs ThreadSanitizer as usual, but hides race reports and collects them in a
- temporary file"""
-
- def __init__(self):
- super(ThreadSanitizerRV1Mixin, self).__init__()
- self.RegisterOptionParserHook(ThreadSanitizerRV1Mixin.ExtendOptionParser)
-
- def ExtendOptionParser(self, parser):
- parser.set_defaults(hybrid="yes")
-
- def CreateAnalyzer(self):
- use_gdb = common.IsMac()
- self.analyzer = ThreadSanitizerRV1Analyzer(self._source_dir, use_gdb)
- return self.analyzer
-
- def Cleanup(self):
- super(ThreadSanitizerRV1Mixin, self).Cleanup()
- self.analyzer.CloseOutputFile()
-
-
-class ThreadSanitizerRV2Mixin(object):
- """RaceVerifier second pass."""
-
- def __init__(self):
- super(ThreadSanitizerRV2Mixin, self).__init__()
- self.RegisterOptionParserHook(ThreadSanitizerRV2Mixin.ExtendOptionParser)
-
- def ExtendOptionParser(self, parser):
- parser.add_option("", "--race-verifier-sleep-ms",
- dest="race_verifier_sleep_ms", default=10,
- help="duration of RaceVerifier delays")
-
- def ToolSpecificFlags(self):
- proc = super(ThreadSanitizerRV2Mixin, self).ToolSpecificFlags()
- proc += ['--race-verifier=%s' % ThreadSanitizerRV1Analyzer.TMP_FILE,
- '--race-verifier-sleep-ms=%d' %
- int(self._options.race_verifier_sleep_ms)]
- return proc
-
- def Cleanup(self):
- super(ThreadSanitizerRV2Mixin, self).Cleanup()
- os.unlink(ThreadSanitizerRV1Analyzer.TMP_FILE)
-
-
-class ThreadSanitizerRV1Posix(ThreadSanitizerRV1Mixin, ThreadSanitizerPosix):
- pass
-
-
-class ThreadSanitizerRV2Posix(ThreadSanitizerRV2Mixin, ThreadSanitizerPosix):
- pass
-
-
-class ThreadSanitizerRV1Windows(ThreadSanitizerRV1Mixin,
- ThreadSanitizerWindows):
- pass
-
-
-class ThreadSanitizerRV2Windows(ThreadSanitizerRV2Mixin,
- ThreadSanitizerWindows):
- pass
-
-
-class RaceVerifier(object):
- """Runs tests under RaceVerifier/Valgrind."""
-
- MORE_INFO_URL = "http://code.google.com/p/data-race-test/wiki/RaceVerifier"
-
- def RV1Factory(self):
- if common.IsWindows():
- return ThreadSanitizerRV1Windows()
- else:
- return ThreadSanitizerRV1Posix()
-
- def RV2Factory(self):
- if common.IsWindows():
- return ThreadSanitizerRV2Windows()
- else:
- return ThreadSanitizerRV2Posix()
-
- def ToolName(self):
- return "tsan"
-
- def Main(self, args, check_sanity, min_runtime_in_seconds):
- logging.info("Running a TSan + RaceVerifier test. For more information, " +
- "see " + self.MORE_INFO_URL)
- cmd1 = self.RV1Factory()
- ret = cmd1.Main(args, check_sanity, min_runtime_in_seconds)
- # Verify race reports, if there are any.
- if ret == -1:
- logging.info("Starting pass 2 of 2. Running the same binary in " +
- "RaceVerifier mode to confirm possible race reports.")
- logging.info("For more information, see " + self.MORE_INFO_URL)
- cmd2 = self.RV2Factory()
- ret = cmd2.Main(args, check_sanity, min_runtime_in_seconds)
- else:
- logging.info("No reports, skipping RaceVerifier second pass")
- logging.info("Please see " + self.MORE_INFO_URL + " for more information " +
- "on RaceVerifier")
- return ret
-
- def Run(self, args, module, min_runtime_in_seconds=0):
- return self.Main(args, False, min_runtime_in_seconds)
-
-
class ToolFactory:
def Create(self, tool_name):
if tool_name == "memcheck":
return Memcheck()
- if tool_name == "tsan":
- if common.IsWindows():
- return ThreadSanitizerWindows()
- else:
- return ThreadSanitizerPosix()
if tool_name == "drmemory" or tool_name == "drmemory_light":
# TODO(timurrrr): remove support for "drmemory" when buildbots are
# switched to drmemory_light OR make drmemory==drmemory_full the default
@@ -1183,8 +826,6 @@ class ToolFactory:
return DrMemory(True, False)
if tool_name == "drmemory_pattern":
return DrMemory(False, True)
- if tool_name == "tsan_rv":
- return RaceVerifier()
try:
platform_name = common.PlatformNames()[0]
except common.NotImplementedError: