OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2009 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 # heapcheck_test.py | 6 # heapcheck_test.py |
7 | 7 |
8 """Wrapper for running the test under heapchecker and analyzing the output.""" | 8 """Wrapper for running the test under heapchecker and analyzing the output.""" |
9 | 9 |
10 import datetime | 10 import datetime |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 0, if all the errors are suppressed and the sanity check passes. | 82 0, if all the errors are suppressed and the sanity check passes. |
83 """ | 83 """ |
84 leak_report = re.compile( | 84 leak_report = re.compile( |
85 'Leak of ([0-9]*) bytes in ([0-9]*) objects allocated from:') | 85 'Leak of ([0-9]*) bytes in ([0-9]*) objects allocated from:') |
86 stack_line = re.compile('\s*@\s*(?:0x)?[0-9a-fA-F]+\s*([^\n]*)') | 86 stack_line = re.compile('\s*@\s*(?:0x)?[0-9a-fA-F]+\s*([^\n]*)') |
87 return_code = 0 | 87 return_code = 0 |
88 # leak signature: [number of bytes, number of objects] | 88 # leak signature: [number of bytes, number of objects] |
89 cur_leak_signature = None | 89 cur_leak_signature = None |
90 cur_stack = [] | 90 cur_stack = [] |
91 cur_report = [] | 91 cur_report = [] |
| 92 reported_hashes = {} |
92 # Statistics grouped by suppression description: | 93 # Statistics grouped by suppression description: |
93 # [hit count, bytes, objects]. | 94 # [hit count, bytes, objects]. |
94 used_suppressions = {} | 95 used_suppressions = {} |
95 for line in log_lines: | 96 for line in log_lines: |
96 line = line.rstrip() # remove the trailing \n | 97 line = line.rstrip() # remove the trailing \n |
97 match = stack_line.match(line) | 98 match = stack_line.match(line) |
98 if match: | 99 if match: |
99 cur_stack.append(match.groups()[0]) | 100 cur_stack.append(match.groups()[0]) |
100 cur_report.append(line) | 101 cur_report.append(line) |
101 continue | 102 continue |
102 else: | 103 else: |
103 if cur_stack: | 104 if cur_stack: |
104 # Try to find the suppression that applies to the current leak stack. | 105 # Try to find the suppression that applies to the current leak stack. |
105 description = '' | 106 description = '' |
106 for supp in self._suppressions: | 107 for supp in self._suppressions: |
107 if supp.Match(cur_stack): | 108 if supp.Match(cur_stack): |
108 cur_stack = [] | 109 cur_stack = [] |
109 description = supp.description | 110 description = supp.description |
110 break | 111 break |
111 if cur_stack: | 112 if cur_stack: |
112 if not cur_leak_signature: | 113 if not cur_leak_signature: |
113 print 'Missing leak signature for the following stack: ' | 114 print 'Missing leak signature for the following stack: ' |
114 for frame in cur_stack: | 115 for frame in cur_stack: |
115 print ' ' + frame | 116 print ' ' + frame |
116 print 'Aborting...' | 117 print 'Aborting...' |
117 return 3 | 118 return 3 |
118 # Print the report and set the return code to 1. | 119 error_hash = hash("".join(cur_stack)) & 0xffffffffffffffff |
119 print ('Leak of %d bytes in %d objects allocated from:' | 120 if error_hash not in reported_hashes: |
120 % tuple(cur_leak_signature)) | 121 reported_hashes[error_hash] = 1 |
121 print '\n'.join(cur_report) | 122 # Print the report and set the return code to 1. |
122 return_code = 1 | 123 print ('Leak of %d bytes in %d objects allocated from:' |
123 # Generate the suppression iff the stack contains more than one | 124 % tuple(cur_leak_signature)) |
124 # frame (otherwise it's likely to be broken) | 125 print '\n'.join(cur_report) |
125 if len(cur_stack) > 1: | 126 return_code = 1 |
126 print '\nSuppression (error hash=#%016X#):\n{' \ | 127 # Generate the suppression iff the stack contains more than one |
127 % (hash("".join(cur_stack)) & 0xffffffffffffffff) | 128 # frame (otherwise it's likely to be broken) |
128 print ' <insert_a_suppression_name_here>' | 129 if len(cur_stack) > 1: |
129 print ' Heapcheck:Leak' | 130 print '\nSuppression (error hash=#%016X#):\n{' % (error_hash) |
130 for frame in cur_stack: | 131 print ' <insert_a_suppression_name_here>' |
131 print ' fun:' + frame | 132 print ' Heapcheck:Leak' |
132 print '}\n\n\n' | 133 for frame in cur_stack: |
133 else: | 134 print ' fun:' + frame |
134 print ('This stack may be broken due to omitted frame pointers. ' | 135 print '}\n\n\n' |
135 'It is not recommended to suppress it.') | 136 else: |
| 137 print ('This stack may be broken due to omitted frame pointers.' |
| 138 ' It is not recommended to suppress it.') |
136 else: | 139 else: |
137 # Update the suppressions histogram. | 140 # Update the suppressions histogram. |
138 if description in used_suppressions: | 141 if description in used_suppressions: |
139 hits, bytes, objects = used_suppressions[description] | 142 hits, bytes, objects = used_suppressions[description] |
140 hits += 1 | 143 hits += 1 |
141 bytes += cur_leak_signature[0] | 144 bytes += cur_leak_signature[0] |
142 objects += cur_leak_signature[1] | 145 objects += cur_leak_signature[1] |
143 used_suppressions[description] = [hits, bytes, objects] | 146 used_suppressions[description] = [hits, bytes, objects] |
144 else: | 147 else: |
145 used_suppressions[description] = [1] + cur_leak_signature | 148 used_suppressions[description] = [1] + cur_leak_signature |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 'http://dev.chromium.org/developers/how-tos/' | 206 'http://dev.chromium.org/developers/how-tos/' |
204 'using-the-heap-leak-checker') | 207 'using-the-heap-leak-checker') |
205 return retcode | 208 return retcode |
206 | 209 |
207 | 210 |
208 def RunTool(args, supp_files, module): | 211 def RunTool(args, supp_files, module): |
209 tool = HeapcheckWrapper(supp_files) | 212 tool = HeapcheckWrapper(supp_files) |
210 MODULES_TO_SANITY_CHECK = ["base"] | 213 MODULES_TO_SANITY_CHECK = ["base"] |
211 check_sanity = module in MODULES_TO_SANITY_CHECK | 214 check_sanity = module in MODULES_TO_SANITY_CHECK |
212 return tool.Main(args[1:], check_sanity) | 215 return tool.Main(args[1:], check_sanity) |
OLD | NEW |