Files
Al Muthanna Athamina 7c055e7ab0 Add logic to the stack analyzer to accommodate TSAN stacktraces
Add custom analysis that is only done if the ClusterFuzz analyzer fails
analyze the stacktrace given without overriding any of its functionality.

Bug: v8:12313
Change-Id: I9e4bc40404387160eb122b8f58999717bd4e7672
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4165085
Commit-Queue: Almothana Athamneh <almuthanna@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85390}
2023-01-19 12:13:36 +00:00

108 lines
3.0 KiB
Python

#!/usr/bin/env python3
# Copyright 2022 the V8 project 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 logging
import os
import re
import sys
ANALYSIS_FAILURE_STATES = ['NULL', 'Unknown', '', None]
STACKFRAME_REGEX = r'^#\d+.*'
FILE_LOCATION_REGEX = r'.*\:\d+\:\d+$'
def fake_clusterfuzz_imports(modules):
for module in modules:
sys.modules[module] = __import__('clusterfuzz_fakes')
def pre_clusterfuzz_import():
local_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(local_path)
fake_clusterfuzz_imports([
'clusterfuzz._internal.platforms.android',
'clusterfuzz._internal.google_cloud_utils',
'clusterfuzz._internal.config.local_config',
])
class CustomStackParser:
def __init__(self):
pre_clusterfuzz_import()
from clusterfuzz.stacktraces import StackParser, MAX_CRASH_STATE_FRAMES
from clusterfuzz.stacktraces import llvm_test_one_input_override
from clusterfuzz.stacktraces import constants
self.MAX_CRASH_STATE_FRAMES = MAX_CRASH_STATE_FRAMES
self.stack_parser = StackParser()
self.constants = constants
self.llvm_test_one_input_override = llvm_test_one_input_override
def analyze_crash(self, stderr):
try:
stderr_analysis = self.stack_parser.parse(stderr)
self.custom_analyzer(stderr_analysis)
return {
"crash_state": stderr_analysis.crash_state.strip(),
"crash_type": stderr_analysis.crash_type.strip(),
}
except Exception as e:
logging.info(e)
return {
"crash_state": "Unknown",
"crash_type": "Unknown",
}
def _extract_function_name(self, frame):
split_frame = frame.split()
start_loc = 1
end_loc = -1
if len(split_frame) > 2 and split_frame[2] == 'in':
start_loc = 3
split_frame = split_frame[start_loc:]
for idx, item in enumerate(split_frame):
# exclude file name and everything after it
if re.match(FILE_LOCATION_REGEX, item):
end_loc = idx
break
if end_loc != -1:
return ' '.join(split_frame[:end_loc])
return None
def _fallback_crash_state(self, stacktrace):
status = []
for line in [l.strip() for l in stacktrace.splitlines()]:
if re.match(STACKFRAME_REGEX, line):
frame = self._extract_function_name(line)
if not self.stack_parser.ignore_stack_frame(frame):
status.append(frame)
if len(status) >= self.MAX_CRASH_STATE_FRAMES:
break
return '\n'.join(status)
def custom_analyzer(self, crash_info):
if crash_info.crash_state in ANALYSIS_FAILURE_STATES:
fallback_state = self._fallback_crash_state(crash_info.crash_stacktrace)
crash_info.crash_state = fallback_state or crash_info.crash_state
class EmptyStackParser:
def analyze_crash(self, stderr):
return {}
def create_stack_parser():
try:
return CustomStackParser()
except ImportError as e:
logging.info(e)
return EmptyStackParser()