Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(523)

Unified Diff: appengine/findit/crash/callstack_detectors.py

Issue 2593593003: [Predator] Add Clusterfuzz stacktrace parser. (Closed)
Patch Set: Rebase and fix nit. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | appengine/findit/crash/chromecrash_parser.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/findit/crash/callstack_detectors.py
diff --git a/appengine/findit/crash/callstack_detectors.py b/appengine/findit/crash/callstack_detectors.py
new file mode 100644
index 0000000000000000000000000000000000000000..6dc2cc60703c6d4ffd225280ae1c6a9ba7fb44e2
--- /dev/null
+++ b/appengine/findit/crash/callstack_detectors.py
@@ -0,0 +1,199 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import re
+
+from crash.type_enums import CallStackFormatType
+from crash.type_enums import LanguageType
+from crash.type_enums import SanitizerType
+
+
+class CallStackDetector(object):
+ """Class for detecting the start of a particular sort of CallStack."""
+
+ # TODO(crbug.com/677321) Make the return to be a namedtuple.
+ def IsStartOfNewCallStack(self, line, flags=None):
+ """Determines whether a line is the start of a new callstack or not.
+
+ Args:
+ line (str): The line to be checked.
+ flags (FlagManager): manager for keeping track of parsing flags.
+
+ Returns:
+ A tuple -
+ (is_new_callstack, priority, format_type, language_type, metadata)
+ is_new_callstack (bool): Boolean indicating whether this is the start of
+ a new callstack.
+ priority (int): Priority of a callstack.
+ format_type (CallStackFormatType): The format of the new callstack, or
+ None if there is no new callstack.
+ language_type (LanguageType): The language of the new callstack, or None
+ if there is no new callstack.
+ metadata (dict): Dict of metadata for the new callstack, e.g. pid of
+ the stack.
+ """
+ raise NotImplementedError()
+
+
+class AndroidJobDetector(CallStackDetector):
+ """Detects the start of an android job callstack."""
+ JAVA_LANG_CALLSTACK_START_PATTERN = r'^java\.[A-Za-z0-9$._]+'
+ JAVA_ORG_GHROMIUM_CALLSTACK_START_PATTERN = r'^org\.chromium\.[A-Za-z0-9$._]+'
+ JAVA_CAUSED_BY_CALLSTACK_START_PATTERN = r'^Caused by:'
+ JAVA_ANDROID_CALLSTACK_START_PATTERN = (
+ r'^(com\.google\.)?android\.[A-Za-z0-9$._]+')
+
+ JAVA_CALLSTACK_START_REGEX = re.compile(
+ '|'.join([JAVA_LANG_CALLSTACK_START_PATTERN,
+ JAVA_ORG_GHROMIUM_CALLSTACK_START_PATTERN,
+ JAVA_CAUSED_BY_CALLSTACK_START_PATTERN,
+ JAVA_ANDROID_CALLSTACK_START_PATTERN]))
+
+ def IsStartOfNewCallStack(self, line, flags=None):
+ if AndroidJobDetector.JAVA_CALLSTACK_START_REGEX.match(line):
+ # Only assign the highest priority to fatal exception stack or segv
+ # stack.
+ if flags and flags.Get('java_main_stack_flag'):
+ flags.TurnOff('java_main_stack_flag')
+ return True, 0, CallStackFormatType.JAVA, LanguageType.JAVA, {}
+
+ return True, 1, CallStackFormatType.JAVA, LanguageType.JAVA, {}
+
+ return False, None, None, None, None
+
+
+class SyzyasanDetector(CallStackDetector):
+ """Detects the start of a syzyasn callstack."""
+ SYZYASAN_CRASH_CALLSTACK_START_REGEX = re.compile(r'^Crash stack:$')
+ SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile(r'^(?!Crash).* stack:$')
+
+ def IsStartOfNewCallStack(self, line, flags=None):
+ # In syzyasan build, new stack starts with 'crash stack:',
+ # 'freed stack:', etc.
+ if SyzyasanDetector.SYZYASAN_CRASH_CALLSTACK_START_REGEX.match(line):
+ return True, 0, CallStackFormatType.SYZYASAN, LanguageType.CPP, {}
+ # Other callstacks all get priority 1.
+ if SyzyasanDetector.SYZYASAN_NON_CRASH_CALLSTACK_START_REGEX.match(line):
+ return True, 1, CallStackFormatType.SYZYASAN, LanguageType.CPP, {}
+
+ return False, None, None, None, None
+
+
+class TsanDetector(CallStackDetector):
+ """Detects the start of a thread sanitizer callstack."""
+ TSAN_CRASH_CALLSTACK_START_PATTERN1 = r'^(Read|Write) of size \d+'
+ TSAN_CRASH_CALLSTACK_START_PATTERN2 = r'^[A-Z]+: ThreadSanitizer'
+ TSAN_ALLOCATION_CALLSTACK_START_PATTERN = (
+ r'^Previous (write|read) of size \d+')
+ TSAN_LOCATION_CALLSTACK_START_PATTERN = (
+ r'^Location is heap block of size \d+')
+
+ TSAN_CRASH_CALLSTACK_START_REGEX = re.compile(
+ '|'.join([TSAN_CRASH_CALLSTACK_START_PATTERN1,
+ TSAN_CRASH_CALLSTACK_START_PATTERN2]))
+
+ TSAN_NON_CRASH_CALLSTACK_START_REGEX = re.compile(
+ '|'.join([TSAN_ALLOCATION_CALLSTACK_START_PATTERN,
+ TSAN_LOCATION_CALLSTACK_START_PATTERN]))
+
+ def IsStartOfNewCallStack(self, line, flags=None):
+ # Crash stack gets priority 0.
+ if TsanDetector.TSAN_CRASH_CALLSTACK_START_REGEX.match(line):
+ return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+
+ # All other stacks get priority 1.
+ if TsanDetector.TSAN_NON_CRASH_CALLSTACK_START_REGEX.match(line):
+ return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+
+ return False, None, None, None, None
+
+
+class UbsanDetector(CallStackDetector):
+ """Detects the start of an undefined-behavior callstack."""
+ UBSAN_CALLSTACK_START_REGEX = re.compile(r'^.*: runtime error: .*$')
+
+ def IsStartOfNewCallStack(self, line, flags=None):
+ if UbsanDetector.UBSAN_CALLSTACK_START_REGEX.match(line):
+ if flags and flags.Get('is_first_stack_flag'):
+ flags.TurnOff('is_first_stack_flag')
+ return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+
+ return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+
+ return False, None, None, None, None
+
+
+class MsanDetector(CallStackDetector):
+ """Detects the start of a memory sanitizer callstack."""
+ MSAN_CALLSTACK_START_REGEX = re.compile(r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)')
+ MSAN_CREATION_CALLSTACK_START_MARKER = 'Uninitialized value was created by'
+ MSAN_STORAGE_CALLSTACK_START_MARKER = 'Uninitialized value was stored to'
+
+ def IsStartOfNewCallStack(self, line, flags=None):
+ # Assign the only msan stack priority 0.
+ if MsanDetector.MSAN_CREATION_CALLSTACK_START_MARKER in line:
+ return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+ if MsanDetector.MSAN_STORAGE_CALLSTACK_START_MARKER in line:
+ return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+ msan_callstack_start_regex = (
+ MsanDetector.MSAN_CALLSTACK_START_REGEX.match(line))
+ if msan_callstack_start_regex:
+ return (True, 2, CallStackFormatType.DEFAULT, LanguageType.CPP,
+ {'pid': int(msan_callstack_start_regex.group(1).strip())})
+
+ return False, None, None, None, None
+
+
+class AsanDetector(CallStackDetector):
+ """Detects the start of an address sanitizer callstack."""
+ ASAN_CRASH_CALLSTACK_START_REGEX1 = re.compile(
+ r'^==(\d+)== ?([A-Z]+:|\w+Sanitizer)')
+ ASAN_CRASH_CALLSTACK_START_REGEX2 = re.compile(
+ r'^(READ|WRITE) of size \d+ at|^backtrace:')
+
+ ASAN_FREED_CALLSTACK_START_PATTERN = (
+ r'^freed by thread T\d+ (.* )?here:')
+ ASAN_ALLOCATION_CALLSTACK_START_PATTERN = (
+ r'^(previously )?allocated by thread T\d+ (.* )?here:')
+ ASAN_OTHER_CALLSTACK_START_PATTERN = (
+ r'^Thread T\d+ (.* )?created by')
+
+ ASAN_NON_CRASH_CALLSTACK_START_PATTERN = re.compile(
+ '|'.join([ASAN_FREED_CALLSTACK_START_PATTERN,
+ ASAN_ALLOCATION_CALLSTACK_START_PATTERN,
+ ASAN_OTHER_CALLSTACK_START_PATTERN]))
+
+ def IsStartOfNewCallStack(self, line, flags=None):
+ asan_crash_callstack_start_regex1_match = (
+ AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX1.match(line))
+ if asan_crash_callstack_start_regex1_match:
+ return (True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP,
+ {'pid': int(
+ asan_crash_callstack_start_regex1_match.group(1).strip())})
+
+ # Crash stack gets priority 0.
+ if AsanDetector.ASAN_CRASH_CALLSTACK_START_REGEX2.match(line):
+ return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+
+ # All other callstack gets priority 1.
+ if AsanDetector.ASAN_NON_CRASH_CALLSTACK_START_PATTERN.match(line):
+ return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+
+ return False, None, None, None, None
+
+
+class ChromeCrashStackDetector(CallStackDetector):
+ """Detects the start of an chromecrash(Fracas/Cracas) callstack."""
+ CHROME_CRASH_CALLSTACK_START_REGEX = re.compile(r'CRASHED \[(.*) @ 0x(.*)\]')
+ JAVA_CALLSTACK_START_REGEX = re.compile(r'\(JAVA\) CRASHED \[(.*) @ 0x(.*)\]')
+
+ def IsStartOfNewCallStack(self, line, flags=None):
+ if ChromeCrashStackDetector.CHROME_CRASH_CALLSTACK_START_REGEX.match(line):
+ # Fracas only provide magic signature stack (crash stack).
+ return True, 0, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
+
+ if ChromeCrashStackDetector.JAVA_CALLSTACK_START_REGEX.match(line):
+ return True, 0, CallStackFormatType.DEFAULT, LanguageType.JAVA, {}
+
+ return False, None, None, None, None
« no previous file with comments | « no previous file | appengine/findit/crash/chromecrash_parser.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698