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 |