|
@@ -0,0 +1,91 @@
|
|
|
+#!/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
|
|
|
+
|
|
|
+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)
|
|
|
+
|
|
|
+# 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.MULTILINE)
|
|
|
+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== <inherited from parent>
|
|
|
+#==21343==
|
|
|
+#==21343== Open file descriptor 2:
|
|
|
+#==21343== <inherited from parent>
|
|
|
+#==21343==
|
|
|
+#==21343== Open file descriptor 1:
|
|
|
+#==21343== <inherited from parent>
|
|
|
+#==21343==
|
|
|
+#==21343== Open file descriptor 0: /dev/pts/1
|
|
|
+#==21343== <inherited from parent>
|
|
|
+
|
|
|
+replace_re = re.compile(r"^=="+str(valgrind_number)+r"==\s+Open file descriptor \d+:\s*[^\s]*$\n^=="+str(valgrind_number)+r"==\s+<inherited from parent>$\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 log_content.isspace():
|
|
|
+ exit(0)
|
|
|
+
|
|
|
+# There is something fishy in the valgrind output, so error-exit
|
|
|
+print(log_content)
|
|
|
+exit(1)
|