#!/usr/bin/env python3 # # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file # for details. All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. # Simple wrapper for running Valgrind and checking the output on # stderr for memory leaks. import subprocess import sys import re VALGRIND_ARGUMENTS = [ 'valgrind', '--error-exitcode=1', '--leak-check=full', '--trace-children=yes', '--ignore-ranges=0x000-0xFFF', # Used for implicit null checks. '--vex-iropt-level=1' # Valgrind crashes with the default level (2). ] # Compute the command line. command = VALGRIND_ARGUMENTS + sys.argv[1:] # Run Valgrind. process = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) code = process.wait() output = process.stdout.readlines() errors = process.stderr.readlines() # Always print the output, but leave out the 3 line banner printed # by certain versions of Valgrind. if len(output) > 0 and output[0].startswith("** VALGRIND_ROOT="): output = output[3:] sys.stdout.writelines(output) # If Valgrind produced an error, we report that to the user. if code != 0: sys.stderr.writelines(errors) sys.exit(code) # Look through the leak details and make sure that we don't have # any definitely or indirectly lost bytes. We allow possibly lost # bytes to lower the risk of false positives. LEAK_RE = r"(?:definitely|indirectly) lost:" LEAK_LINE_MATCHER = re.compile(LEAK_RE) LEAK_OKAY_MATCHER = re.compile(r"lost: 0 bytes in 0 blocks") leaks = [] for line in errors: if LEAK_LINE_MATCHER.search(line): leaks.append(line) if not LEAK_OKAY_MATCHER.search(line): sys.stderr.writelines(errors) sys.exit(1) # Make sure we found the right number of leak lines. if not len(leaks) in [0, 2, 3]: sys.stderr.writelines(errors) sys.stderr.write('\n\n#### Malformed Valgrind output.\n#### Exiting.\n') sys.exit(1) # Success. sys.exit(0)