Chromium Code Reviews| 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 re | 5 import re |
| 6 | 6 |
| 7 from crash.stacktrace import CallStack | |
| 8 from crash.type_enums import LanguageType | |
| 9 | |
| 7 _INLINE_FUNCTION_FILE_PATH_MARKERS = [ | 10 _INLINE_FUNCTION_FILE_PATH_MARKERS = [ |
| 8 'third_party/llvm-build/Release+Asserts/include/c++/v1/', | 11 'third_party/llvm-build/Release+Asserts/include/c++/v1/', |
| 9 'linux/debian_wheezy_amd64-sysroot/usr/include/c++/4.6/bits/', | 12 'linux/debian_wheezy_amd64-sysroot/usr/include/c++/4.6/bits/', |
| 10 'eglibc-3GlaMS/eglibc-2.19/sysdeps/unix/', | 13 'eglibc-3GlaMS/eglibc-2.19/sysdeps/unix/', |
| 11 ] | 14 ] |
| 12 | 15 |
| 16 # When checking the null pointer deference, any deference of a address within | |
|
wrengr
2016/12/19 23:51:05
"deference" -> "dereference"
"a address" -> "an a
Sharu Jiang
2016/12/22 01:59:43
Done.
| |
| 17 # the threshold is considered as null pointer deference. Be consistent with | |
|
wrengr
2016/12/19 23:51:05
ditto
Sharu Jiang
2016/12/22 01:59:43
Done.
| |
| 18 # the threshold used in Clusterfuzz. | |
| 19 NULL_POINTER_DEREFERENCE_THRESHOLD = 4096 | |
| 20 V8_JIT_CODE_MARKER = 'v8::internal::Invoke' | |
| 21 V8_API_H_FILE_PATH = 'src/api.h' | |
| 22 V8_API_CC_FILE_PATH = 'src/api.cc' | |
|
stgao
2016/12/20 19:07:36
Could we make a list instead of two separate files
Sharu Jiang
2016/12/22 01:59:43
Actually making it seperate would make the impleme
| |
| 23 V8_DEP_PATH_MARKER = 'src/v8' | |
| 24 BLINK_BINDINGS_GENERATED_PATH_REGEX = re.compile( | |
| 25 r'out/[^/]+/gen/blink/bindings/.*') | |
| 26 JAVA_JRE_SDK_REGEX = re.compile( | |
| 27 r'(java\..*|javax\..*|org\.xml\..*|org\.w3c\..*|' | |
| 28 r'org\.omg\..*|org\.ietf\.jgss\..*)') | |
| 29 | |
| 13 | 30 |
| 14 class CallStackFilter(object): | 31 class CallStackFilter(object): |
| 15 """Filters frames of a callstack buffer.""" | 32 """Filters frames of a callstack buffer.""" |
| 16 | 33 |
| 17 def __call__(self, stack_buffer): | 34 def __call__(self, stack_buffer): |
| 18 """Returns the stack_buffer with frames filtered. | 35 """Returns the stack_buffer with frames filtered. |
| 19 | 36 |
| 20 Args: | 37 Args: |
| 21 stack_buffer (CallStackBuffer): stack buffer to be filtered. | 38 stack_buffer (CallStackBuffer): stack buffer to be filtered. |
| 22 """ | 39 """ |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 def __call__(self, stack_buffer): | 72 def __call__(self, stack_buffer): |
| 56 """Returns stack_buffer with only top n frames. | 73 """Returns stack_buffer with only top n frames. |
| 57 | 74 |
| 58 If no self.top_n_frames is None, don't do any filtering. | 75 If no self.top_n_frames is None, don't do any filtering. |
| 59 """ | 76 """ |
| 60 if self.top_n_frames is None: | 77 if self.top_n_frames is None: |
| 61 return stack_buffer | 78 return stack_buffer |
| 62 | 79 |
| 63 stack_buffer.frames = stack_buffer.frames[:self.top_n_frames] | 80 stack_buffer.frames = stack_buffer.frames[:self.top_n_frames] |
| 64 return stack_buffer | 81 return stack_buffer |
| 82 | |
| 83 | |
| 84 class FilterJavaJreSdkFrames(CallStackFilter): | |
|
wrengr
2016/12/19 23:51:05
It's inconsistent to lowercase JRE and SDK here wh
Sharu Jiang
2016/12/22 01:59:43
This is because if it is ``FilterJavaJRESDKFrames`
wrengr
2016/12/22 23:31:51
yeah, JRESDK is hard to read too (though slightly
Sharu Jiang
2016/12/23 00:33:20
Ok... let's leave it as it is then.
| |
| 85 """Filter out package names from Java JRE/SDK. | |
|
stgao
2016/12/20 19:07:36
nit: "Filter" -> "Filters"
Same for other occurre
Sharu Jiang
2016/12/22 01:59:43
Done.
| |
| 86 | |
| 87 For example: java.*, javax.*, org.xml.*, org.w3c.*, org.omg.*, | |
| 88 org.ietf.jgss.*. These frames are misleading to Predator. | |
| 89 """ | |
| 90 def __call__(self, stack_buffer): | |
| 91 if stack_buffer.language_type != LanguageType.JAVA: | |
| 92 return stack_buffer | |
| 93 | |
| 94 stack_buffer.frames = filter( | |
| 95 lambda frame: not JAVA_JRE_SDK_REGEX.match(frame.function), | |
| 96 stack_buffer.frames) | |
| 97 return stack_buffer | |
| 98 | |
| 99 | |
| 100 class KeepV8FramesIfV8GeneratedJITCrash(CallStackFilter): | |
| 101 """Keeps v8 frames if conditions met. | |
| 102 | |
| 103 If the top-most frames don't have symbols, but the top frame that does is | |
| 104 ``v8::internal::Invoke``, the bug is likely a crash in | |
| 105 V8's generated JIT code. | |
| 106 """ | |
| 107 def __call__(self, stack_buffer): | |
| 108 if (stack_buffer and V8_JIT_CODE_MARKER in stack_buffer.frames[0].function | |
| 109 and stack_buffer.metadata.get('top_frame_has_no_symbols')): | |
| 110 stack_buffer.frames = filter(lambda f: V8_DEP_PATH_MARKER in f.dep_path, | |
| 111 stack_buffer.frames) | |
| 112 return stack_buffer | |
| 113 | |
| 114 | |
| 115 class FilterV8FramesForV8APIBindingCode(CallStackFilter): | |
| 116 """Filter all v8 frames if conditions met. | |
|
wrengr
2016/12/19 23:51:05
should clarify whether it's all conditions or any
Sharu Jiang
2016/12/22 01:59:43
Done.
| |
| 117 | |
| 118 Conditions: | |
| 119 (1) src/v8/src/api.h or src/v8/src/api.cc appears as | |
| 120 the top file in the stack trace. | |
| 121 (2) the second file is not in src/v8/src | |
| 122 (e.g. src/out/Release/gen/blink/bindings) or the crash is caused by | |
| 123 dereference of null pointer, then V8 should not be responsible for | |
| 124 the crash (likely a bindings issue). | |
|
stgao
2016/12/20 19:07:36
nit: Could we fill in the whole line before moving
Sharu Jiang
2016/12/22 01:59:43
Done.
| |
| 125 | |
| 126 Args: | |
| 127 crash_address: Address where crash happens. | |
|
wrengr
2016/12/19 23:51:05
type?
Sharu Jiang
2016/12/22 01:59:43
Done.
| |
| 128 | |
| 129 Returns: | |
|
stgao
2016/12/20 19:07:36
What is the Returns for? I'm confused here.
Sharu Jiang
2016/12/22 01:59:43
Oops, this should be removed.
| |
| 130 A string of hint message. | |
| 131 """ | |
| 132 def __init__(self, crash_address=None): | |
| 133 # Record the crash address of the to-be-parsed stack_buffer. | |
| 134 self.crash_address = crash_address | |
| 135 | |
| 136 def __call__(self, stack_buffer): | |
| 137 if len(stack_buffer.frames) < 2: | |
| 138 return stack_buffer | |
| 139 | |
| 140 first_frame_is_api_file = ( | |
| 141 V8_DEP_PATH_MARKER in stack_buffer.frames[0].dep_path and | |
| 142 (V8_API_H_FILE_PATH == stack_buffer.frames[0].file_path or | |
| 143 V8_API_CC_FILE_PATH == stack_buffer.frames[0].file_path)) | |
| 144 | |
| 145 second_frame_not_from_v8_src = ( | |
| 146 V8_DEP_PATH_MARKER not in stack_buffer.frames[1].dep_path or | |
| 147 not stack_buffer.frames[1].file_path.startswith('src')) | |
| 148 | |
| 149 null_pointer_dereference = False | |
| 150 if self.crash_address: | |
| 151 try: | |
| 152 null_pointer_dereference = int( | |
| 153 self.crash_address, | |
| 154 base=16) < NULL_POINTER_DEREFERENCE_THRESHOLD | |
| 155 except ValueError: # pragma: no cover | |
| 156 # some testcases like memcpy-param-overlap have crash addresses like | |
| 157 # '[0x621000017d00,0x621000018cea) and [0x621000017d16, 0x621000018d00)' | |
| 158 pass | |
| 159 | |
| 160 if (first_frame_is_api_file and (second_frame_not_from_v8_src or | |
| 161 null_pointer_dereference)): | |
| 162 stack_buffer.frames = filter( | |
| 163 lambda f: V8_DEP_PATH_MARKER not in f.dep_path, | |
| 164 stack_buffer.frames) | |
| 165 # After deleting all v8 frames, if the top n frames are generated code, | |
| 166 # need to filter them out. | |
| 167 top_n_generated_code_frames = 0 | |
| 168 for frame in stack_buffer.frames: | |
| 169 if not BLINK_BINDINGS_GENERATED_PATH_REGEX.match(frame.file_path): | |
| 170 break | |
| 171 top_n_generated_code_frames += 1 | |
| 172 stack_buffer.frames = stack_buffer.frames[top_n_generated_code_frames:] | |
| 173 | |
| 174 return stack_buffer | |
| 175 | |
| 176 | |
| 177 class FilterFramesAfterBlinkGeneratedCode(CallStackFilter): | |
| 178 """Filter all the frames after blink generated code.""" | |
| 179 def __call__(self, stack_buffer): | |
| 180 for index, frame in enumerate(stack_buffer): | |
| 181 if BLINK_BINDINGS_GENERATED_PATH_REGEX.match(frame.file_path): | |
| 182 stack_buffer.frames = stack_buffer.frames[:index] | |
| 183 break | |
|
stgao
2016/12/20 19:07:36
What if there are two frames with generated code?
Sharu Jiang
2016/12/22 01:59:43
This is to filter generated frames and frames afte
| |
| 184 | |
| 185 return stack_buffer | |
| 186 | |
| 187 | |
| 188 class FilterV8FramesIfV8NotInTopFrames(CallStackFilter): | |
| 189 """Filter all v8 frames if there is no v8 frames in top_n_frames.""" | |
| 190 def __init__(self, top_n_frames=4): | |
| 191 self.top_n_frames = top_n_frames | |
| 192 | |
| 193 def __call__(self, stack_buffer): | |
| 194 need_filter_v8 = False | |
| 195 for index, frame in enumerate(stack_buffer): | |
| 196 if index >= self.top_n_frames: | |
| 197 need_filter_v8 = True | |
| 198 break | |
| 199 | |
| 200 if V8_DEP_PATH_MARKER in frame.dep_path: | |
| 201 break | |
| 202 | |
| 203 if not need_filter_v8: | |
| 204 return stack_buffer | |
| 205 | |
| 206 stack_buffer.frames = filter( | |
| 207 lambda f: not V8_DEP_PATH_MARKER in f.dep_path, stack_buffer.frames) | |
|
wrengr
2016/12/19 23:51:05
The syntax "x not in xs" is more standard than "no
Sharu Jiang
2016/12/22 01:59:43
Done.
| |
| 208 return stack_buffer | |
| OLD | NEW |