#!/usr/bin/env python # coding: UTF-8 # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # This script checks the valgrind output for errors. # The track-fds does not cause an error if there are too many FDs open, # therefore we parse the output and fail if there are open FDs import sys import subprocess import os.path import re import os logfile = sys.argv[1] valgrind_command = ' '.join('"' + item + '"' for item in sys.argv[2:]) # Execute a command and output its stdout text def execute(command): process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Poll process for new output until finished while True: nextline = process.stdout.readline().decode('utf-8') if nextline == '' and process.poll() is not None: break sys.stdout.write(nextline) sys.stdout.flush() return process.returncode ret_code = execute(valgrind_command) if not os.path.isfile(logfile): print("### PYTHON ERROR: Valgrind logfile does not exist: " + logfile) exit(1) log_content = "" with open(logfile, 'r') as content_file: log_content = content_file.read() if len(log_content) == 0: print("### PYTHON ERROR: Valgrind logfile is empty: " + logfile) exit(1) # Remove output of possible bug in OSX # --16672-- run: /usr/bin/dsymutil "/Users/travis/build/Pro/open62541/build/bin/tests/check_utils" # --16672-- WARNING: unhandled amd64-darwin syscall: unix:464 # --16672-- You may be able to write your own handler. # --16672-- Read the file README_MISSING_SYSCALL_OR_IOCTL. # --16672-- Nevertheless we consider this a bug. Please report # --16672-- it at http://valgrind.org/support/bug_reports.html. replace_re = re.compile(r"^--(\d+)--\s+run: .*-- it at http://valgrind.org/support/bug_reports.html\.$\n", re.MULTILINE | re.DOTALL) log_content = replace_re.sub('', log_content) # Try to parse the output. Look for the following line: # ==17054== FILE DESCRIPTORS: 5 open at exit. descriptors_re = re.compile(r".*==(\d+)==\s+FILE DESCRIPTORS: (\d+) open at exit\..*", re.DOTALL) m = descriptors_re.match(log_content) if not m: print("### PYTHON ERROR: File descriptors header not found: " + logfile) print(log_content) exit(1) log_content = descriptors_re.sub('', log_content) valgrind_number = m.group(1) open_count = int(m.group(2)) # Remove the open file descriptors which are inherited from parent. they look like this: #==21343== Open file descriptor 3: /home/user/open62541/build/bin/tests/discovery.log #==21343== #==21343== #==21343== Open file descriptor 2: #==21343== #==21343== #==21343== Open file descriptor 1: #==21343== #==21343== #==21343== Open file descriptor 0: /dev/pts/1 #==21343== replace_re = re.compile(r"^=="+str(valgrind_number)+r"==\s+Open file descriptor \d+:\s*[^\s]*$\n^=="+str(valgrind_number)+r"==\s+$\n(^=="+str(valgrind_number)+r"==\s+$\n)*", re.MULTILINE) log_content = replace_re.sub('', log_content) # Valgrind detected a memleak if ret_code != 0 if ret_code != 0: print(log_content) exit(ret_code) # No issues by valgrind if len(log_content) == 0 or log_content.isspace(): exit(0) # There is something fishy in the valgrind output, so error-exit print(log_content) exit(1)