| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # suppressions.py | 6 # suppressions.py |
| 7 | 7 |
| 8 """Post-process Valgrind suppression matcher. | 8 """Post-process Valgrind suppression matcher. |
| 9 | 9 |
| 10 Suppressions are defined as follows: | 10 Suppressions are defined as follows: |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 supp_filename = JOIN(suppressions_root, "memcheck", "suppressions_mac.txt") | 58 supp_filename = JOIN(suppressions_root, "memcheck", "suppressions_mac.txt") |
| 59 vg_mac = ReadSuppressionsFromFile(supp_filename) | 59 vg_mac = ReadSuppressionsFromFile(supp_filename) |
| 60 supp_filename = JOIN(suppressions_root, "tsan", "suppressions_mac.txt") | 60 supp_filename = JOIN(suppressions_root, "tsan", "suppressions_mac.txt") |
| 61 tsan_mac = ReadSuppressionsFromFile(supp_filename) | 61 tsan_mac = ReadSuppressionsFromFile(supp_filename) |
| 62 result['mac_suppressions'] = vg_mac + tsan_mac | 62 result['mac_suppressions'] = vg_mac + tsan_mac |
| 63 | 63 |
| 64 supp_filename = JOIN(suppressions_root, "tsan", "suppressions_win32.txt") | 64 supp_filename = JOIN(suppressions_root, "tsan", "suppressions_win32.txt") |
| 65 tsan_win = ReadSuppressionsFromFile(supp_filename) | 65 tsan_win = ReadSuppressionsFromFile(supp_filename) |
| 66 result['win_suppressions'] = tsan_win | 66 result['win_suppressions'] = tsan_win |
| 67 | 67 |
| 68 supp_filename = JOIN(suppressions_root, "..", "heapcheck", "suppressions.txt") | |
| 69 result['heapcheck_suppressions'] = ReadSuppressionsFromFile(supp_filename) | |
| 70 | |
| 71 supp_filename = JOIN(suppressions_root, "drmemory", "suppressions.txt") | 68 supp_filename = JOIN(suppressions_root, "drmemory", "suppressions.txt") |
| 72 result['drmem_suppressions'] = ReadSuppressionsFromFile(supp_filename) | 69 result['drmem_suppressions'] = ReadSuppressionsFromFile(supp_filename) |
| 73 supp_filename = JOIN(suppressions_root, "drmemory", "suppressions_full.txt") | 70 supp_filename = JOIN(suppressions_root, "drmemory", "suppressions_full.txt") |
| 74 result['drmem_full_suppressions'] = ReadSuppressionsFromFile(supp_filename) | 71 result['drmem_full_suppressions'] = ReadSuppressionsFromFile(supp_filename) |
| 75 | 72 |
| 76 return result | 73 return result |
| 77 | 74 |
| 78 | 75 |
| 79 def GlobToRegex(glob_pattern, ignore_case=False): | 76 def GlobToRegex(glob_pattern, ignore_case=False): |
| 80 """Translate glob wildcards (*?) into regex syntax. Escape the rest.""" | 77 """Translate glob wildcards (*?) into regex syntax. Escape the rest.""" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 if not self.stack: | 140 if not self.stack: |
| 144 return False | 141 return False |
| 145 lines = [f.strip() for f in suppression_from_report] | 142 lines = [f.strip() for f in suppression_from_report] |
| 146 return self.regex.match('\n'.join(lines) + '\n') is not None | 143 return self.regex.match('\n'.join(lines) + '\n') is not None |
| 147 | 144 |
| 148 | 145 |
| 149 def FilenameToTool(filename): | 146 def FilenameToTool(filename): |
| 150 """Return the name of the tool that a file is related to, or None. | 147 """Return the name of the tool that a file is related to, or None. |
| 151 | 148 |
| 152 Example mappings: | 149 Example mappings: |
| 153 tools/heapcheck/suppressions.txt -> heapcheck | |
| 154 tools/valgrind/tsan/suppressions.txt -> tsan | 150 tools/valgrind/tsan/suppressions.txt -> tsan |
| 155 tools/valgrind/drmemory/suppressions.txt -> drmemory | 151 tools/valgrind/drmemory/suppressions.txt -> drmemory |
| 156 tools/valgrind/drmemory/suppressions_full.txt -> drmemory | 152 tools/valgrind/drmemory/suppressions_full.txt -> drmemory |
| 157 tools/valgrind/memcheck/suppressions.txt -> memcheck | 153 tools/valgrind/memcheck/suppressions.txt -> memcheck |
| 158 tools/valgrind/memcheck/suppressions_mac.txt -> memcheck | 154 tools/valgrind/memcheck/suppressions_mac.txt -> memcheck |
| 159 """ | 155 """ |
| 160 filename = os.path.abspath(filename) | 156 filename = os.path.abspath(filename) |
| 161 parts = filename.split(os.sep) | 157 parts = filename.split(os.sep) |
| 162 tool = parts[-2] | 158 tool = parts[-2] |
| 163 if tool in ('heapcheck', 'drmemory', 'memcheck', 'tsan'): | 159 if tool in ('drmemory', 'memcheck', 'tsan'): |
| 164 return tool | 160 return tool |
| 165 return None | 161 return None |
| 166 | 162 |
| 167 | 163 |
| 168 def ReadSuppressionsFromFile(filename): | 164 def ReadSuppressionsFromFile(filename): |
| 169 """Read suppressions from the given file and return them as a list""" | 165 """Read suppressions from the given file and return them as a list""" |
| 170 tool_to_parser = { | 166 tool_to_parser = { |
| 171 "drmemory": ReadDrMemorySuppressions, | 167 "drmemory": ReadDrMemorySuppressions, |
| 172 "memcheck": ReadValgrindStyleSuppressions, | 168 "memcheck": ReadValgrindStyleSuppressions, |
| 173 "tsan": ReadValgrindStyleSuppressions, | 169 "tsan": ReadValgrindStyleSuppressions, |
| 174 "heapcheck": ReadValgrindStyleSuppressions, | |
| 175 } | 170 } |
| 176 tool = FilenameToTool(filename) | 171 tool = FilenameToTool(filename) |
| 177 assert tool in tool_to_parser, ( | 172 assert tool in tool_to_parser, ( |
| 178 "unknown tool %s for filename %s" % (tool, filename)) | 173 "unknown tool %s for filename %s" % (tool, filename)) |
| 179 parse_func = tool_to_parser[tool] | 174 parse_func = tool_to_parser[tool] |
| 180 | 175 |
| 181 # Consider non-existent files to be empty. | 176 # Consider non-existent files to be empty. |
| 182 if not os.path.exists(filename): | 177 if not os.path.exists(filename): |
| 183 return [] | 178 return [] |
| 184 | 179 |
| 185 input_file = file(filename, 'r') | 180 input_file = file(filename, 'r') |
| 186 try: | 181 try: |
| 187 return parse_func(input_file, filename) | 182 return parse_func(input_file, filename) |
| 188 except SuppressionError: | 183 except SuppressionError: |
| 189 input_file.close() | 184 input_file.close() |
| 190 raise | 185 raise |
| 191 | 186 |
| 192 | 187 |
| 193 class ValgrindStyleSuppression(Suppression): | 188 class ValgrindStyleSuppression(Suppression): |
| 194 """A suppression using the Valgrind syntax. | 189 """A suppression using the Valgrind syntax. |
| 195 | 190 |
| 196 Most tools, even ones that are not Valgrind-based, use this syntax, ie | 191 Most tools, even ones that are not Valgrind-based, use this syntax, ie |
| 197 Heapcheck, TSan, etc. | 192 TSan, etc. |
| 198 | 193 |
| 199 Attributes: | 194 Attributes: |
| 200 Same as Suppression. | 195 Same as Suppression. |
| 201 """ | 196 """ |
| 202 | 197 |
| 203 def __init__(self, description, type, stack, defined_at): | 198 def __init__(self, description, type, stack, defined_at): |
| 204 """Creates a suppression using the Memcheck, TSan, and Heapcheck syntax.""" | 199 """Creates a suppression using the Memcheck and TSan, syntax.""" |
| 205 regex = '{\n.*\n%s\n' % type | 200 regex = '{\n.*\n%s\n' % type |
| 206 for line in stack: | 201 for line in stack: |
| 207 if line == ELLIPSIS: | 202 if line == ELLIPSIS: |
| 208 regex += '(.*\n)*' | 203 regex += '(.*\n)*' |
| 209 else: | 204 else: |
| 210 regex += GlobToRegex(line) | 205 regex += GlobToRegex(line) |
| 211 regex += '\n' | 206 regex += '\n' |
| 212 regex += '(.*\n)*' | 207 regex += '(.*\n)*' |
| 213 regex += '}' | 208 regex += '}' |
| 214 | 209 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 "%s:%d" % (supp_descriptor, nline))) | 290 "%s:%d" % (supp_descriptor, nline))) |
| 296 cur_descr = '' | 291 cur_descr = '' |
| 297 cur_type = '' | 292 cur_type = '' |
| 298 cur_stack = [] | 293 cur_stack = [] |
| 299 in_suppression = False | 294 in_suppression = False |
| 300 elif not cur_descr: | 295 elif not cur_descr: |
| 301 cur_descr = line | 296 cur_descr = line |
| 302 continue | 297 continue |
| 303 elif not cur_type: | 298 elif not cur_type: |
| 304 if (not line.startswith("Memcheck:") and | 299 if (not line.startswith("Memcheck:") and |
| 305 not line.startswith("ThreadSanitizer:") and | 300 not line.startswith("ThreadSanitizer:")): |
| 306 (line != "Heapcheck:Leak")): | |
| 307 raise SuppressionError( | 301 raise SuppressionError( |
| 308 'Expected "Memcheck:TYPE", "ThreadSanitizer:TYPE" ' | 302 'Expected "Memcheck:TYPE" or "ThreadSanitizer:TYPE", ' |
| 309 'or "Heapcheck:Leak", got "%s"' % line, | 303 'got "%s"' % line, |
| 310 "%s:%d" % (supp_descriptor, nline)) | 304 "%s:%d" % (supp_descriptor, nline)) |
| 311 supp_type = line.split(':')[1] | 305 supp_type = line.split(':')[1] |
| 312 if not supp_type in ["Addr1", "Addr2", "Addr4", "Addr8", | 306 if not supp_type in ["Addr1", "Addr2", "Addr4", "Addr8", |
| 313 "Cond", "Free", "Jump", "Leak", "Overlap", "Param", | 307 "Cond", "Free", "Jump", "Leak", "Overlap", "Param", |
| 314 "Value1", "Value2", "Value4", "Value8", | 308 "Value1", "Value2", "Value4", "Value8", |
| 315 "Race", "UnlockNonLocked", "InvalidLock", | 309 "Race", "UnlockNonLocked", "InvalidLock", |
| 316 "Unaddressable", "Uninitialized"]: | 310 "Unaddressable", "Uninitialized"]: |
| 317 raise SuppressionError('Unknown suppression type "%s"' % supp_type, | 311 raise SuppressionError('Unknown suppression type "%s"' % supp_type, |
| 318 "%s:%d" % (supp_descriptor, nline)) | 312 "%s:%d" % (supp_descriptor, nline)) |
| 319 cur_type = line | 313 cur_type = line |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 test_memcheck_stack_4 = """{ | 622 test_memcheck_stack_4 = """{ |
| 629 test | 623 test |
| 630 Memcheck:Addr4 | 624 Memcheck:Addr4 |
| 631 fun:absolutly | 625 fun:absolutly |
| 632 fun:brilliant | 626 fun:brilliant |
| 633 obj:condition | 627 obj:condition |
| 634 fun:detection | 628 fun:detection |
| 635 fun:expression | 629 fun:expression |
| 636 }""" | 630 }""" |
| 637 | 631 |
| 638 test_heapcheck_stack = """{ | |
| 639 test | |
| 640 Heapcheck:Leak | |
| 641 fun:absolutly | |
| 642 fun:brilliant | |
| 643 obj:condition | |
| 644 fun:detection | |
| 645 fun:expression | |
| 646 }""" | |
| 647 | |
| 648 test_tsan_stack = """{ | 632 test_tsan_stack = """{ |
| 649 test | 633 test |
| 650 ThreadSanitizer:Race | 634 ThreadSanitizer:Race |
| 651 fun:absolutly | 635 fun:absolutly |
| 652 fun:brilliant | 636 fun:brilliant |
| 653 obj:condition | 637 obj:condition |
| 654 fun:detection | 638 fun:detection |
| 655 fun:expression | 639 fun:expression |
| 656 }""" | 640 }""" |
| 657 | 641 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 ] | 673 ] |
| 690 | 674 |
| 691 positive_memcheck_suppressions_4 = [ | 675 positive_memcheck_suppressions_4 = [ |
| 692 "{\nzzz\nMemcheck:Addr4\nfun:absolutly\n}", | 676 "{\nzzz\nMemcheck:Addr4\nfun:absolutly\n}", |
| 693 "{\nzzz\nMemcheck:Unaddressable\nfun:absolutly\n}", | 677 "{\nzzz\nMemcheck:Unaddressable\nfun:absolutly\n}", |
| 694 "{\nzzz\nMemcheck:Addr4\nfun:absolutly\nfun:brilliant\n}", | 678 "{\nzzz\nMemcheck:Addr4\nfun:absolutly\nfun:brilliant\n}", |
| 695 "{\nzzz\nMemcheck:Unaddressable\n...\nfun:brilliant\n}", | 679 "{\nzzz\nMemcheck:Unaddressable\n...\nfun:brilliant\n}", |
| 696 "{\nzzz\nMemcheck:Addr4\n...\nfun:detection\n}", | 680 "{\nzzz\nMemcheck:Addr4\n...\nfun:detection\n}", |
| 697 ] | 681 ] |
| 698 | 682 |
| 699 positive_heapcheck_suppressions = [ | |
| 700 "{\nzzz\nHeapcheck:Leak\n...\nobj:condition\n}", | |
| 701 "{\nzzz\nHeapcheck:Leak\nfun:absolutly\n}", | |
| 702 ] | |
| 703 | |
| 704 positive_tsan_suppressions = [ | 683 positive_tsan_suppressions = [ |
| 705 "{\nzzz\nThreadSanitizer:Race\n...\nobj:condition\n}", | 684 "{\nzzz\nThreadSanitizer:Race\n...\nobj:condition\n}", |
| 706 "{\nzzz\nThreadSanitizer:Race\nfun:absolutly\n}", | 685 "{\nzzz\nThreadSanitizer:Race\nfun:absolutly\n}", |
| 707 ] | 686 ] |
| 708 | 687 |
| 709 negative_memcheck_suppressions_1 = [ | 688 negative_memcheck_suppressions_1 = [ |
| 710 "{\nzzz\nMemcheck:Leak\nfun:abnormal\n}", | 689 "{\nzzz\nMemcheck:Leak\nfun:abnormal\n}", |
| 711 "{\nzzz\nMemcheck:Leak\nfun:ab*liant\n}", | 690 "{\nzzz\nMemcheck:Leak\nfun:ab*liant\n}", |
| 712 "{\nzzz\nMemcheck:Leak\nfun:brilliant\n}", | 691 "{\nzzz\nMemcheck:Leak\nfun:brilliant\n}", |
| 713 "{\nzzz\nMemcheck:Leak\nobj:condition\n}", | 692 "{\nzzz\nMemcheck:Leak\nobj:condition\n}", |
| (...skipping 23 matching lines...) Expand all Loading... |
| 737 "{\nzzz\nMemcheck:Addr1\nfun:abnormal\n}", | 716 "{\nzzz\nMemcheck:Addr1\nfun:abnormal\n}", |
| 738 "{\nzzz\nMemcheck:Addr4\nfun:abnormal\n}", | 717 "{\nzzz\nMemcheck:Addr4\nfun:abnormal\n}", |
| 739 "{\nzzz\nMemcheck:Unaddressable\nfun:abnormal\n}", | 718 "{\nzzz\nMemcheck:Unaddressable\nfun:abnormal\n}", |
| 740 "{\nzzz\nMemcheck:Addr1\nfun:absolutly\n}", | 719 "{\nzzz\nMemcheck:Addr1\nfun:absolutly\n}", |
| 741 "{\nzzz\nMemcheck:Addr2\nfun:ab*liant\n}", | 720 "{\nzzz\nMemcheck:Addr2\nfun:ab*liant\n}", |
| 742 "{\nzzz\nMemcheck:Value4\nfun:brilliant\n}", | 721 "{\nzzz\nMemcheck:Value4\nfun:brilliant\n}", |
| 743 "{\nzzz\nMemcheck:Leak\nobj:condition\n}", | 722 "{\nzzz\nMemcheck:Leak\nobj:condition\n}", |
| 744 "{\nzzz\nMemcheck:Addr8\nfun:brilliant\n}", | 723 "{\nzzz\nMemcheck:Addr8\nfun:brilliant\n}", |
| 745 ] | 724 ] |
| 746 | 725 |
| 747 negative_heapcheck_suppressions = [ | |
| 748 "{\nzzz\nMemcheck:Leak\nfun:absolutly\n}", | |
| 749 "{\nzzz\nHeapcheck:Leak\nfun:brilliant\n}", | |
| 750 ] | |
| 751 | |
| 752 negative_tsan_suppressions = [ | 726 negative_tsan_suppressions = [ |
| 753 "{\nzzz\nThreadSanitizer:Leak\nfun:absolutly\n}", | 727 "{\nzzz\nThreadSanitizer:Leak\nfun:absolutly\n}", |
| 754 "{\nzzz\nThreadSanitizer:Race\nfun:brilliant\n}", | 728 "{\nzzz\nThreadSanitizer:Race\nfun:brilliant\n}", |
| 755 ] | 729 ] |
| 756 | 730 |
| 757 TestStack(test_memcheck_stack_1, | 731 TestStack(test_memcheck_stack_1, |
| 758 positive_memcheck_suppressions_1, | 732 positive_memcheck_suppressions_1, |
| 759 negative_memcheck_suppressions_1) | 733 negative_memcheck_suppressions_1) |
| 760 TestStack(test_memcheck_stack_2, | 734 TestStack(test_memcheck_stack_2, |
| 761 positive_memcheck_suppressions_2, | 735 positive_memcheck_suppressions_2, |
| 762 negative_memcheck_suppressions_2) | 736 negative_memcheck_suppressions_2) |
| 763 TestStack(test_memcheck_stack_3, | 737 TestStack(test_memcheck_stack_3, |
| 764 positive_memcheck_suppressions_3, | 738 positive_memcheck_suppressions_3, |
| 765 negative_memcheck_suppressions_3) | 739 negative_memcheck_suppressions_3) |
| 766 TestStack(test_memcheck_stack_4, | 740 TestStack(test_memcheck_stack_4, |
| 767 positive_memcheck_suppressions_4, | 741 positive_memcheck_suppressions_4, |
| 768 negative_memcheck_suppressions_4) | 742 negative_memcheck_suppressions_4) |
| 769 TestStack(test_heapcheck_stack, positive_heapcheck_suppressions, | |
| 770 negative_heapcheck_suppressions) | |
| 771 TestStack(test_tsan_stack, positive_tsan_suppressions, | 743 TestStack(test_tsan_stack, positive_tsan_suppressions, |
| 772 negative_tsan_suppressions) | 744 negative_tsan_suppressions) |
| 773 | 745 |
| 774 # TODO(timurrrr): add TestFailPresubmit tests. | 746 # TODO(timurrrr): add TestFailPresubmit tests. |
| 775 | 747 |
| 776 ### DrMemory self tests. | 748 ### DrMemory self tests. |
| 777 | 749 |
| 778 # http://crbug.com/96010 suppression. | 750 # http://crbug.com/96010 suppression. |
| 779 stack_96010 = """{ | 751 stack_96010 = """{ |
| 780 UNADDRESSABLE ACCESS | 752 UNADDRESSABLE ACCESS |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 953 bad_stack_frame = """ | 925 bad_stack_frame = """ |
| 954 UNADDRESSABLE ACCESS | 926 UNADDRESSABLE ACCESS |
| 955 name=http://crbug.com/1234 | 927 name=http://crbug.com/1234 |
| 956 fun:memcheck_style_frame | 928 fun:memcheck_style_frame |
| 957 """ | 929 """ |
| 958 TestFailPresubmit(bad_stack_frame, 'Unexpected stack frame pattern', | 930 TestFailPresubmit(bad_stack_frame, 'Unexpected stack frame pattern', |
| 959 suppression_parser=ReadDrMemorySuppressions) | 931 suppression_parser=ReadDrMemorySuppressions) |
| 960 | 932 |
| 961 # Test FilenameToTool. | 933 # Test FilenameToTool. |
| 962 filenames_to_tools = { | 934 filenames_to_tools = { |
| 963 "tools/heapcheck/suppressions.txt": "heapcheck", | |
| 964 "tools/valgrind/tsan/suppressions.txt": "tsan", | 935 "tools/valgrind/tsan/suppressions.txt": "tsan", |
| 965 "tools/valgrind/drmemory/suppressions.txt": "drmemory", | 936 "tools/valgrind/drmemory/suppressions.txt": "drmemory", |
| 966 "tools/valgrind/drmemory/suppressions_full.txt": "drmemory", | 937 "tools/valgrind/drmemory/suppressions_full.txt": "drmemory", |
| 967 "tools/valgrind/memcheck/suppressions.txt": "memcheck", | 938 "tools/valgrind/memcheck/suppressions.txt": "memcheck", |
| 968 "tools/valgrind/memcheck/suppressions_mac.txt": "memcheck", | 939 "tools/valgrind/memcheck/suppressions_mac.txt": "memcheck", |
| 969 "asdf/tools/valgrind/memcheck/suppressions_mac.txt": "memcheck", | 940 "asdf/tools/valgrind/memcheck/suppressions_mac.txt": "memcheck", |
| 970 "foo/bar/baz/tools/valgrind/memcheck/suppressions_mac.txt": "memcheck", | 941 "foo/bar/baz/tools/valgrind/memcheck/suppressions_mac.txt": "memcheck", |
| 971 "foo/bar/baz/tools/valgrind/suppressions.txt": None, | 942 "foo/bar/baz/tools/valgrind/suppressions.txt": None, |
| 972 "tools/valgrind/suppressions.txt": None, | 943 "tools/valgrind/suppressions.txt": None, |
| 973 } | 944 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1009 "instruction=test 0x08(%eax) $0x01\n" | 980 "instruction=test 0x08(%eax) $0x01\n" |
| 1010 "ntdll.dll!*\n" | 981 "ntdll.dll!*\n" |
| 1011 "*!foo\n") | 982 "*!foo\n") |
| 1012 assert str(supp) == supp_str, ( | 983 assert str(supp) == supp_str, ( |
| 1013 "str(supp) != supp_str:\nleft: %s\nright: %s" % (str(supp), supp_str)) | 984 "str(supp) != supp_str:\nleft: %s\nright: %s" % (str(supp), supp_str)) |
| 1014 | 985 |
| 1015 | 986 |
| 1016 if __name__ == '__main__': | 987 if __name__ == '__main__': |
| 1017 SelfTest() | 988 SelfTest() |
| 1018 print 'PASS' | 989 print 'PASS' |
| OLD | NEW |