| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import logging | 5 import logging |
| 6 import re |
| 6 | 7 |
| 7 | 8 |
| 8 class Stacktrace(list): | 9 class Stacktrace(list): |
| 9 """Interface Represents Stacktrace object. | 10 """Interface Represents Stacktrace object. |
| 10 | 11 |
| 11 Contains a list of callstacks, because one stacktrace may have more than | 12 Contains a list of callstacks, because one stacktrace may have more than |
| 12 one callstacks.""" | 13 one callstacks.""" |
| 13 def __init__(self, stack_list=None): | 14 def __init__(self, stack_list=None, signature=None): |
| 14 super(Stacktrace, self).__init__(stack_list or []) | 15 super(Stacktrace, self).__init__(stack_list or []) |
| 15 | 16 |
| 16 def GetCrashStack(self): | 17 if signature: |
| 18 # Filter out the types of signature, for example [Out of Memory]. |
| 19 signature = re.sub('[[][^]]*[]]\s*', '', signature) |
| 20 |
| 21 self.signature = signature |
| 22 self._crash_stack = None |
| 23 |
| 24 @property |
| 25 def crash_stack(self): |
| 17 """Gets the crash stack with the highest (lowest number) priority in | 26 """Gets the crash stack with the highest (lowest number) priority in |
| 18 stacktrace.""" | 27 stacktrace.""" |
| 19 if not self: | 28 if not self: |
| 20 logging.warning('Cannot get crash stack for empty stacktrace: %s', self) | 29 logging.warning('Cannot get crash stack for empty stacktrace: %s', self) |
| 21 return None | 30 return None |
| 22 | 31 |
| 23 # Return the first stack with the least priority. The smaller the number, | 32 if self._crash_stack is None and self.signature: |
| 24 # the higher the priority beginning with 0. | 33 # For clusterfuzz crash, the signature is crash state, it is usually the |
| 25 return sorted(self, key=lambda stack: stack.priority)[0] | 34 # top 3 crash functions seperated by '\n'. |
| 35 signature_parts = self.signature.split('\n') |
| 36 |
| 37 def _IsSignatureCallstack(callstack): |
| 38 for index, frame in enumerate(callstack): |
| 39 for signature_part in signature_parts: |
| 40 if signature_part in frame.function: |
| 41 return True, index |
| 42 |
| 43 return False, 0 |
| 44 |
| 45 # Set the crash stack using signature callstack. |
| 46 for callstack in self: |
| 47 is_signature_callstack, index = _IsSignatureCallstack(callstack) |
| 48 if is_signature_callstack: |
| 49 # Filter all the stack frames before signature. |
| 50 callstack[:] = callstack[index:] |
| 51 self._crash_stack = callstack |
| 52 break |
| 53 |
| 54 # If there is no signature callstack, fall back to set crash stack using |
| 55 # the first least priority callstack. |
| 56 if self._crash_stack is None: |
| 57 self._crash_stack = sorted(self, key=lambda stack: stack.priority)[0] |
| 58 |
| 59 return self._crash_stack |
| OLD | NEW |