| Index: appengine/findit/crash/callstack_detectors.py
|
| diff --git a/appengine/findit/crash/callstack_detectors.py b/appengine/findit/crash/callstack_detectors.py
|
| index 6dc2cc60703c6d4ffd225280ae1c6a9ba7fb44e2..7839db1d2b8672f91680079cbd870328e62fee77 100644
|
| --- a/appengine/findit/crash/callstack_detectors.py
|
| +++ b/appengine/findit/crash/callstack_detectors.py
|
| @@ -2,6 +2,7 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| +from collections import namedtuple
|
| import re
|
|
|
| from crash.type_enums import CallStackFormatType
|
| @@ -9,11 +10,37 @@ from crash.type_enums import LanguageType
|
| from crash.type_enums import SanitizerType
|
|
|
|
|
| +class StartOfCallStack(
|
| + namedtuple('StartOfCallStack',
|
| + ['priority', 'format_type', 'language_type', 'metadata'])):
|
| + """Represents the start of a new callstack.
|
| +
|
| + Properties:
|
| + priority (int): Priority of the new callstack.
|
| + format_type (CallStackFormatType): The format of the new callstack.
|
| + language_type (LanguageType): The language of the new callstack.
|
| + metadata (dict): Dict of metadata for the new callstack, e.g. pid of the
|
| + stack.
|
| + """
|
| + __slots__ = ()
|
| +
|
| + def __new__(cls, priority, format_type, language_type, metadata=None):
|
| + return super(cls, StartOfCallStack).__new__(cls, priority, format_type,
|
| + language_type, metadata or {})
|
| +
|
| + def __str__(self): # pragma: no cover
|
| + return ('%s(priority = %d, format_type = %d, '
|
| + 'language_type = %d, metadata = %s)' % (self.__class__.__name__,
|
| + self.priority,
|
| + self.format_type,
|
| + self.language_type,
|
| + self.metadata))
|
| +
|
| +
|
| 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):
|
| + def __call__(self, line, flags=None):
|
| """Determines whether a line is the start of a new callstack or not.
|
|
|
| Args:
|
| @@ -21,17 +48,7 @@ class CallStackDetector(object):
|
| 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.
|
| + A ``StartOfCallStack`` or None if no callstack found.
|
| """
|
| raise NotImplementedError()
|
|
|
| @@ -50,17 +67,19 @@ class AndroidJobDetector(CallStackDetector):
|
| JAVA_CAUSED_BY_CALLSTACK_START_PATTERN,
|
| JAVA_ANDROID_CALLSTACK_START_PATTERN]))
|
|
|
| - def IsStartOfNewCallStack(self, line, flags=None):
|
| + def __call__(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 StartOfCallStack(0, CallStackFormatType.JAVA,
|
| + LanguageType.JAVA, {})
|
|
|
| - return True, 1, CallStackFormatType.JAVA, LanguageType.JAVA, {}
|
| + return StartOfCallStack(1, CallStackFormatType.JAVA,
|
| + LanguageType.JAVA, {})
|
|
|
| - return False, None, None, None, None
|
| + return None
|
|
|
|
|
| class SyzyasanDetector(CallStackDetector):
|
| @@ -68,16 +87,18 @@ class SyzyasanDetector(CallStackDetector):
|
| 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):
|
| + def __call__(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, {}
|
| + return StartOfCallStack(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 StartOfCallStack(1, CallStackFormatType.SYZYASAN,
|
| + LanguageType.CPP, {})
|
|
|
| - return False, None, None, None, None
|
| + return None
|
|
|
|
|
| class TsanDetector(CallStackDetector):
|
| @@ -97,31 +118,35 @@ class TsanDetector(CallStackDetector):
|
| '|'.join([TSAN_ALLOCATION_CALLSTACK_START_PATTERN,
|
| TSAN_LOCATION_CALLSTACK_START_PATTERN]))
|
|
|
| - def IsStartOfNewCallStack(self, line, flags=None):
|
| + def __call__(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, {}
|
| + return StartOfCallStack(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 StartOfCallStack(1, CallStackFormatType.DEFAULT,
|
| + LanguageType.CPP, {})
|
|
|
| - return False, None, None, None, None
|
| + return 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):
|
| + def __call__(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 StartOfCallStack(0, CallStackFormatType.DEFAULT,
|
| + LanguageType.CPP, {})
|
|
|
| - return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
|
| + return StartOfCallStack(1, CallStackFormatType.DEFAULT,
|
| + LanguageType.CPP, {})
|
|
|
| - return False, None, None, None, None
|
| + return None
|
|
|
|
|
| class MsanDetector(CallStackDetector):
|
| @@ -130,19 +155,22 @@ class MsanDetector(CallStackDetector):
|
| 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):
|
| + def __call__(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, {}
|
| + return StartOfCallStack(0, CallStackFormatType.DEFAULT,
|
| + LanguageType.CPP, {})
|
| if MsanDetector.MSAN_STORAGE_CALLSTACK_START_MARKER in line:
|
| - return True, 1, CallStackFormatType.DEFAULT, LanguageType.CPP, {}
|
| + return StartOfCallStack(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 StartOfCallStack(
|
| + 2, CallStackFormatType.DEFAULT, LanguageType.CPP,
|
| + {'pid': int(msan_callstack_start_regex.group(1).strip())})
|
|
|
| - return False, None, None, None, None
|
| + return None
|
|
|
|
|
| class AsanDetector(CallStackDetector):
|
| @@ -164,23 +192,26 @@ class AsanDetector(CallStackDetector):
|
| ASAN_ALLOCATION_CALLSTACK_START_PATTERN,
|
| ASAN_OTHER_CALLSTACK_START_PATTERN]))
|
|
|
| - def IsStartOfNewCallStack(self, line, flags=None):
|
| + def __call__(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())})
|
| + return StartOfCallStack(
|
| + 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, {}
|
| + return StartOfCallStack(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 StartOfCallStack(1, CallStackFormatType.DEFAULT,
|
| + LanguageType.CPP, {})
|
|
|
| - return False, None, None, None, None
|
| + return None
|
|
|
|
|
| class ChromeCrashStackDetector(CallStackDetector):
|
| @@ -188,12 +219,14 @@ class ChromeCrashStackDetector(CallStackDetector):
|
| 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):
|
| + def __call__(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, {}
|
| + return StartOfCallStack(0, CallStackFormatType.DEFAULT,
|
| + LanguageType.CPP, {})
|
|
|
| if ChromeCrashStackDetector.JAVA_CALLSTACK_START_REGEX.match(line):
|
| - return True, 0, CallStackFormatType.DEFAULT, LanguageType.JAVA, {}
|
| + return StartOfCallStack(0, CallStackFormatType.DEFAULT,
|
| + LanguageType.JAVA, {})
|
|
|
| - return False, None, None, None, None
|
| + return None
|
|
|