aboutsummaryrefslogtreecommitdiff
path: root/llvm_tools/bisect_clang_crashes.py
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_tools/bisect_clang_crashes.py')
-rwxr-xr-xllvm_tools/bisect_clang_crashes.py240
1 files changed, 130 insertions, 110 deletions
diff --git a/llvm_tools/bisect_clang_crashes.py b/llvm_tools/bisect_clang_crashes.py
index c53db179..b2759051 100755
--- a/llvm_tools/bisect_clang_crashes.py
+++ b/llvm_tools/bisect_clang_crashes.py
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-# Copyright 2020 The Chromium OS Authors. All rights reserved.
+# Copyright 2020 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Fetches and submits the artifacts from Chrome OS toolchain's crash bucket.
+"""Fetches and submits the artifacts from ChromeOS toolchain's crash bucket.
"""
import argparse
@@ -21,117 +21,137 @@ import chroot
def get_artifacts(pattern):
- results = subprocess.check_output(['gsutil.py', 'ls', pattern],
- stderr=subprocess.STDOUT,
- encoding='utf-8')
- return sorted(l.strip() for l in results.splitlines())
+ results = subprocess.check_output(
+ ["gsutil.py", "ls", pattern], stderr=subprocess.STDOUT, encoding="utf-8"
+ )
+ return sorted(l.strip() for l in results.splitlines())
def get_crash_reproducers(working_dir):
- results = []
- for src in [
- f for f in glob.glob('%s/*.c*' % working_dir)
- if f.split('.')[-1] in ['c', 'cc', 'cpp']
- ]:
- script = '.'.join(src.split('.')[:-1]) + '.sh'
- if not os.path.exists(script):
- logging.warning('could not find the matching script of %s', src)
- else:
- results.append((src, script))
- return results
-
-
-def submit_crash_to_forcey(forcey: str, temporary_directory: str,
- buildbucket_id: str, url: str) -> None:
- dest_dir = os.path.join(temporary_directory, buildbucket_id)
- dest_file = os.path.join(dest_dir, os.path.basename(url))
- logging.info('Downloading and submitting %r...', url)
- subprocess.check_output(['gsutil.py', 'cp', url, dest_file],
- stderr=subprocess.STDOUT)
- subprocess.check_output(['tar', '-xJf', dest_file], cwd=dest_dir)
- for src, script in get_crash_reproducers(dest_dir):
- subprocess.check_output([
- forcey, 'reduce', '-wait=false', '-note',
- '%s:%s' % (url, src), '-sh_file', script, '-src_file', src
- ])
+ results = []
+ for src in [
+ f
+ for f in glob.glob("%s/*.c*" % working_dir)
+ if f.split(".")[-1] in ["c", "cc", "cpp"]
+ ]:
+ script = ".".join(src.split(".")[:-1]) + ".sh"
+ if not os.path.exists(script):
+ logging.warning("could not find the matching script of %s", src)
+ else:
+ results.append((src, script))
+ return results
+
+
+def submit_crash_to_forcey(
+ forcey: str, temporary_directory: str, buildbucket_id: str, url: str
+) -> None:
+ dest_dir = os.path.join(temporary_directory, buildbucket_id)
+ dest_file = os.path.join(dest_dir, os.path.basename(url))
+ logging.info("Downloading and submitting %r...", url)
+ subprocess.check_output(
+ ["gsutil.py", "cp", url, dest_file], stderr=subprocess.STDOUT
+ )
+ subprocess.check_output(["tar", "-xJf", dest_file], cwd=dest_dir)
+ for src, script in get_crash_reproducers(dest_dir):
+ subprocess.check_output(
+ [
+ forcey,
+ "reduce",
+ "-wait=false",
+ "-note",
+ "%s:%s" % (url, src),
+ "-sh_file",
+ script,
+ "-src_file",
+ src,
+ ]
+ )
def main(argv):
- chroot.VerifyOutsideChroot()
- logging.basicConfig(
- format='%(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: %(message)s',
- level=logging.INFO,
- )
- cur_dir = os.path.dirname(os.path.abspath(__file__))
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- '--4c', dest='forcey', required=True, help='Path to a 4c client binary')
- parser.add_argument(
- '--state_file',
- default=os.path.join(cur_dir, 'chromeos-state.json'),
- help='The path to the state file.')
- parser.add_argument(
- '--nocleanup',
- action='store_false',
- dest='cleanup',
- help='Keep temporary files created after the script finishes.')
- opts = parser.parse_args(argv)
-
- state_file = os.path.abspath(opts.state_file)
- os.makedirs(os.path.dirname(state_file), exist_ok=True)
- temporary_directory = '/tmp/bisect_clang_crashes'
- os.makedirs(temporary_directory, exist_ok=True)
- urls = get_artifacts('gs://chromeos-toolchain-artifacts/clang-crash-diagnoses'
- '/**/*clang_crash_diagnoses.tar.xz')
- logging.info('%d crash URLs found', len(urls))
-
- visited = {}
- if os.path.exists(state_file):
- buildbucket_ids = {url.split('/')[-2] for url in urls}
- with open(state_file, encoding='utf-8') as f:
- data = json.load(f)
- visited = {k: v for k, v in data.items() if k in buildbucket_ids}
- logging.info('Successfully loaded %d previously-submitted crashes',
- len(visited))
-
- try:
- for url in urls:
- splits = url.split('/')
- buildbucket_id = splits[-2]
- # Skip the builds that has been processed
- if buildbucket_id in visited:
- continue
- submit_crash_to_forcey(
- forcey=opts.forcey,
- temporary_directory=temporary_directory,
- buildbucket_id=buildbucket_id,
- url=url,
- )
- visited[buildbucket_id] = url
-
- exception_in_flight = False
- except:
- exception_in_flight = True
- raise
- finally:
- if exception_in_flight:
- # This is best-effort. If the machine powers off or similar, we'll just
- # resubmit the same crashes, which is suboptimal, but otherwise
- # acceptable.
- logging.error('Something went wrong; attempting to save our work...')
- else:
- logging.info('Persisting state...')
-
- tmp_state_file = state_file + '.tmp'
- with open(tmp_state_file, 'w', encoding='utf-8') as f:
- json.dump(visited, f, indent=2)
- os.rename(tmp_state_file, state_file)
-
- logging.info('State successfully persisted')
-
- if opts.cleanup:
- shutil.rmtree(temporary_directory)
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
+ chroot.VerifyOutsideChroot()
+ logging.basicConfig(
+ format="%(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: %(message)s",
+ level=logging.INFO,
+ )
+ cur_dir = os.path.dirname(os.path.abspath(__file__))
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "--4c", dest="forcey", required=True, help="Path to a 4c client binary"
+ )
+ parser.add_argument(
+ "--state_file",
+ default=os.path.join(cur_dir, "chromeos-state.json"),
+ help="The path to the state file.",
+ )
+ parser.add_argument(
+ "--nocleanup",
+ action="store_false",
+ dest="cleanup",
+ help="Keep temporary files created after the script finishes.",
+ )
+ opts = parser.parse_args(argv)
+
+ state_file = os.path.abspath(opts.state_file)
+ os.makedirs(os.path.dirname(state_file), exist_ok=True)
+ temporary_directory = "/tmp/bisect_clang_crashes"
+ os.makedirs(temporary_directory, exist_ok=True)
+ urls = get_artifacts(
+ "gs://chromeos-toolchain-artifacts/clang-crash-diagnoses"
+ "/**/*clang_crash_diagnoses.tar.xz"
+ )
+ logging.info("%d crash URLs found", len(urls))
+
+ visited = {}
+ if os.path.exists(state_file):
+ buildbucket_ids = {url.split("/")[-2] for url in urls}
+ with open(state_file, encoding="utf-8") as f:
+ data = json.load(f)
+ visited = {k: v for k, v in data.items() if k in buildbucket_ids}
+ logging.info(
+ "Successfully loaded %d previously-submitted crashes", len(visited)
+ )
+
+ try:
+ for url in urls:
+ splits = url.split("/")
+ buildbucket_id = splits[-2]
+ # Skip the builds that has been processed
+ if buildbucket_id in visited:
+ continue
+ submit_crash_to_forcey(
+ forcey=opts.forcey,
+ temporary_directory=temporary_directory,
+ buildbucket_id=buildbucket_id,
+ url=url,
+ )
+ visited[buildbucket_id] = url
+
+ exception_in_flight = False
+ except:
+ exception_in_flight = True
+ raise
+ finally:
+ if exception_in_flight:
+ # This is best-effort. If the machine powers off or similar, we'll just
+ # resubmit the same crashes, which is suboptimal, but otherwise
+ # acceptable.
+ logging.error(
+ "Something went wrong; attempting to save our work..."
+ )
+ else:
+ logging.info("Persisting state...")
+
+ tmp_state_file = state_file + ".tmp"
+ with open(tmp_state_file, "w", encoding="utf-8") as f:
+ json.dump(visited, f, indent=2)
+ os.rename(tmp_state_file, state_file)
+
+ logging.info("State successfully persisted")
+
+ if opts.cleanup:
+ shutil.rmtree(temporary_directory)
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))