class TSanReportExtractor(ReportExtractor): """Extract ThreadSanitizer reports""" __category_names = ['data race', 'thread leak'] __start_line_pattern = re.compile( '^warning: threadsanitizer: (?P<category>[a-z ]+) \(', re.IGNORECASE) __start_last_line_pattern = re.compile('^={18}$', re.MULTILINE) __end_line_pattern = __start_last_line_pattern def __init__(self, options): super(TSanReportExtractor, self).__init__(options, Sanitizer('ThreadSanitizer', 'tsan')) self.__printer = Printer(options) def collect(self): for category in self.__category_names: self._collect_reports(category) def extract(self, last_line, line): if self._extract_continue(line): if self.__end_line_pattern.search(line): self._extract_end() else: search = self.__start_line_pattern.search(line) if search and self.__start_last_line_pattern.search(last_line): category = search.group('category').lower() if not category in self.__category_names: self.__printer.bailout('unkown category ' + repr(category)) else: self._extract_start( self._make_and_add_report(True, category)) self._extract_continue(last_line + line)
class TaskEliminateDuplicateReports(object): description = 'Eliminating duplicate reports ...' __tsan_data_race_max_stack_frames = 3 def __init__(self, bank): self.__bank = bank def setup(self, options): self.__printer = Printer(options) self.__duplicate_reports = [] self.__identifiers_funcs = { 'tsan': { 'data race': self.__tsan_data_race_identifiers, 'thread leak': self.__tsan_thread_leak_identifiers } } # TODO: split into separate lists for sanitizers and categories for better performance self.__known_identifiers = [] def process(self, report): if not self.__identifiers_funcs.get(report.sanitizer.name_short, {}).get(report.category_name): self.__printer.bailout('unable to analyse ' + str(report)) identifiers = self.__identifiers_funcs[report.sanitizer.name_short][ report.category_name](report) if not identifiers: self.__printer.bailout('unable to extract identifiers from ' + str(report)) for identifier in identifiers: if identifier in self.__known_identifiers: self.__printer.task_info('removing ' + str(report)) self.__duplicate_reports.append(report) return self.__known_identifiers.extend(identifiers) def teardown(self): for report in self.__duplicate_reports: self.__bank.remove_report(report) def __tsan_data_race_identifiers(self, report): fragments = [] for stack in report.call_stacks: if 'tsan_data_race_type' in stack.special: fragment = [ stack.special.get('tsan_data_race_type'), stack.special.get('tsan_data_race_bytes') ] for i in range( min(len(stack.frames), self.__tsan_data_race_max_stack_frames)): fragment.extend([ stack.frames[i].src_file_rel_path, stack.frames[i].func_name, stack.frames[i].line_num, stack.frames[i].char_pos ]) fragments.append(':'.join( ['?' if not f else str(f) for f in fragment])) if len(fragments) == 1: return fragments if len(fragments) == 2: # either way is fine! return [ fragments[0] + ':' + fragments[1], fragments[1] + ':' + fragments[0] ] def __tsan_thread_leak_identifiers(self, report): for stack in report.call_stacks: if stack.special.get('tsan_thread_leak_thread_name'): return [stack.special['tsan_thread_leak_thread_name']]