build/valgrind/output_handler.py

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 from __future__ import print_function, unicode_literals
michael@0 6
michael@0 7 import re
michael@0 8
michael@0 9 class OutputHandler(object):
michael@0 10 '''
michael@0 11 A class for handling Valgrind output.
michael@0 12
michael@0 13 Valgrind errors look like this:
michael@0 14
michael@0 15 ==60741== 40 (24 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record 2,746 of 5,235
michael@0 16 ==60741== at 0x4C26B43: calloc (vg_replace_malloc.c:593)
michael@0 17 ==60741== by 0x63AEF65: PR_Calloc (prmem.c:443)
michael@0 18 ==60741== by 0x69F236E: PORT_ZAlloc_Util (secport.c:117)
michael@0 19 ==60741== by 0x69F1336: SECITEM_AllocItem_Util (secitem.c:28)
michael@0 20 ==60741== by 0xA04280B: ffi_call_unix64 (in /builds/slave/m-in-l64-valgrind-000000000000/objdir/toolkit/library/libxul.so)
michael@0 21 ==60741== by 0xA042443: ffi_call (ffi64.c:485)
michael@0 22
michael@0 23 For each such error, this class extracts most or all of the first (error
michael@0 24 kind) line, plus the function name in each of the first few stack entries.
michael@0 25 With this data it constructs and prints a TEST-UNEXPECTED-FAIL message that
michael@0 26 TBPL will highlight.
michael@0 27
michael@0 28 It buffers these lines from which text is extracted so that the
michael@0 29 TEST-UNEXPECTED-FAIL message can be printed before the full error.
michael@0 30
michael@0 31 Parsing the Valgrind output isn't ideal, and it may break in the future if
michael@0 32 Valgrind changes the format of the messages, or introduces new error kinds.
michael@0 33 To protect against this, we also count how many lines containing
michael@0 34 "<insert_a_suppression_name_here>" are seen. Thanks to the use of
michael@0 35 --gen-suppressions=yes, exactly one of these lines is present per error. If
michael@0 36 the count of these lines doesn't match the error count found during
michael@0 37 parsing, then the parsing has missed one or more errors and we can fail
michael@0 38 appropriately.
michael@0 39 '''
michael@0 40
michael@0 41 def __init__(self):
michael@0 42 # The regexps in this list match all of Valgrind's errors. Note that
michael@0 43 # Valgrind is English-only, so we don't have to worry about
michael@0 44 # localization.
michael@0 45 self.re_error = \
michael@0 46 r'==\d+== (' + \
michael@0 47 r'(Use of uninitialised value of size \d+)|' + \
michael@0 48 r'(Conditional jump or move depends on uninitialised value\(s\))|' + \
michael@0 49 r'(Syscall param .* contains uninitialised byte\(s\))|' + \
michael@0 50 r'(Syscall param .* points to (unaddressable|uninitialised) byte\(s\))|' + \
michael@0 51 r'((Unaddressable|Uninitialised) byte\(s\) found during client check request)|' + \
michael@0 52 r'(Invalid free\(\) / delete / delete\[\] / realloc\(\))|' + \
michael@0 53 r'(Mismatched free\(\) / delete / delete \[\])|' + \
michael@0 54 r'(Invalid (read|write) of size \d+)|' + \
michael@0 55 r'(Jump to the invalid address stated on the next line)|' + \
michael@0 56 r'(Source and destination overlap in .*)|' + \
michael@0 57 r'(.* bytes in .* blocks are .* lost)' + \
michael@0 58 r')'
michael@0 59 # Match identifer chars, plus ':' for namespaces, and '\?' in order to
michael@0 60 # match "???" which Valgrind sometimes produces.
michael@0 61 self.re_stack_entry = r'^==\d+==.*0x[A-Z0-9]+: ([A-Za-z0-9_:\?]+)'
michael@0 62 self.re_suppression = r' *<insert_a_suppression_name_here>'
michael@0 63 self.error_count = 0
michael@0 64 self.suppression_count = 0
michael@0 65 self.number_of_stack_entries_to_get = 0
michael@0 66 self.curr_failure_msg = None
michael@0 67 self.buffered_lines = None
michael@0 68
michael@0 69 def __call__(self, line):
michael@0 70 if self.number_of_stack_entries_to_get == 0:
michael@0 71 # Look for the start of a Valgrind error.
michael@0 72 m = re.search(self.re_error, line)
michael@0 73 if m:
michael@0 74 self.error_count += 1
michael@0 75 self.number_of_stack_entries_to_get = 4
michael@0 76 self.curr_failure_msg = 'TEST-UNEXPECTED-FAIL | valgrind-test | ' + m.group(1) + " at "
michael@0 77 self.buffered_lines = [line]
michael@0 78 else:
michael@0 79 print(line)
michael@0 80
michael@0 81 else:
michael@0 82 # We've recently found a Valgrind error, and are now extracting
michael@0 83 # details from the first few stack entries.
michael@0 84 self.buffered_lines.append(line)
michael@0 85 m = re.match(self.re_stack_entry, line)
michael@0 86 if m:
michael@0 87 self.curr_failure_msg += m.group(1)
michael@0 88 else:
michael@0 89 self.curr_failure_msg += '?!?'
michael@0 90
michael@0 91 self.number_of_stack_entries_to_get -= 1
michael@0 92 if self.number_of_stack_entries_to_get != 0:
michael@0 93 self.curr_failure_msg += ' / '
michael@0 94 else:
michael@0 95 # We've finished getting the first few stack entries. Print the
michael@0 96 # failure message and the buffered lines, and then reset state.
michael@0 97 print('\n' + self.curr_failure_msg + '\n')
michael@0 98 for b in self.buffered_lines:
michael@0 99 print(b)
michael@0 100 self.curr_failure_msg = None
michael@0 101 self.buffered_lines = None
michael@0 102
michael@0 103 if re.match(self.re_suppression, line):
michael@0 104 self.suppression_count += 1
michael@0 105

mercurial