valgrind_check_error.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #!/usr/bin/env python
  2. # coding: UTF-8
  3. # This Source Code Form is subject to the terms of the Mozilla Public
  4. # License, v. 2.0. If a copy of the MPL was not distributed with this
  5. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. # This script checks the valgrind output for errors.
  7. # The track-fds does not cause an error if there are too many FDs open,
  8. # therefore we parse the output and fail if there are open FDs
  9. import sys
  10. import subprocess
  11. import os.path
  12. import re
  13. import os
  14. logfile = sys.argv[1]
  15. valgrind_command = ' '.join('"' + item + '"' for item in sys.argv[2:])
  16. # Execute a command and output its stdout text
  17. def execute(command):
  18. process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  19. # Poll process for new output until finished
  20. while True:
  21. nextline = process.stdout.readline().decode('utf-8')
  22. if nextline == '' and process.poll() is not None:
  23. break
  24. sys.stdout.write(nextline)
  25. sys.stdout.flush()
  26. return process.returncode
  27. ret_code = execute(valgrind_command)
  28. if not os.path.isfile(logfile):
  29. print("### PYTHON ERROR: Valgrind logfile does not exist: " + logfile)
  30. exit(1)
  31. log_content = ""
  32. with open(logfile, 'r') as content_file:
  33. log_content = content_file.read()
  34. if len(log_content) == 0:
  35. print("### PYTHON ERROR: Valgrind logfile is empty: " + logfile)
  36. exit(1)
  37. # Remove output of possible bug in OSX
  38. # --16672-- run: /usr/bin/dsymutil "/Users/travis/build/Pro/open62541/build/bin/tests/check_utils"
  39. # --16672-- WARNING: unhandled amd64-darwin syscall: unix:464
  40. # --16672-- You may be able to write your own handler.
  41. # --16672-- Read the file README_MISSING_SYSCALL_OR_IOCTL.
  42. # --16672-- Nevertheless we consider this a bug. Please report
  43. # --16672-- it at http://valgrind.org/support/bug_reports.html.
  44. replace_re = re.compile(r"^--(\d+)--\s+run: .*-- it at http://valgrind.org/support/bug_reports.html\.$\n", re.MULTILINE | re.DOTALL)
  45. log_content = replace_re.sub('', log_content)
  46. # Try to parse the output. Look for the following line:
  47. # ==17054== FILE DESCRIPTORS: 5 open at exit.
  48. descriptors_re = re.compile(r".*==(\d+)==\s+FILE DESCRIPTORS: (\d+) open at exit\..*", re.DOTALL)
  49. m = descriptors_re.match(log_content)
  50. if not m:
  51. print("### PYTHON ERROR: File descriptors header not found: " + logfile)
  52. print(log_content)
  53. exit(1)
  54. log_content = descriptors_re.sub('', log_content)
  55. valgrind_number = m.group(1)
  56. open_count = int(m.group(2))
  57. # Remove the open file descriptors which are inherited from parent. they look like this:
  58. #==21343== Open file descriptor 3: /home/user/open62541/build/bin/tests/discovery.log
  59. #==21343== <inherited from parent>
  60. #==21343==
  61. #==21343== Open file descriptor 2:
  62. #==21343== <inherited from parent>
  63. #==21343==
  64. #==21343== Open file descriptor 1:
  65. #==21343== <inherited from parent>
  66. #==21343==
  67. #==21343== Open file descriptor 0: /dev/pts/1
  68. #==21343== <inherited from parent>
  69. 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)
  70. log_content = replace_re.sub('', log_content)
  71. # Valgrind detected a memleak if ret_code != 0
  72. if ret_code != 0:
  73. print(log_content)
  74. exit(ret_code)
  75. # No issues by valgrind
  76. if len(log_content) == 0 or log_content.isspace():
  77. exit(0)
  78. # There is something fishy in the valgrind output, so error-exit
  79. print(log_content)
  80. exit(1)