| Index: tools/valgrind/valgrind_test.py
|
| diff --git a/tools/valgrind/valgrind_test.py b/tools/valgrind/valgrind_test.py
|
| index 24fa32acb49850935a7ccbdd846b9fb08de821a7..5576ed3177655d43038fc6e24609227e95610000 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:
|
|
|