| #!/usr/bin/env python3 | |
| # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| # for details. All rights reserved. Use of this source code is governed by a | |
| # BSD-style license that can be found in the LICENSE file. | |
| import os | |
| import cpplint | |
| import re | |
| USE_PYTHON3 = True | |
| # memcpy does not handle overlapping memory regions. Even though this | |
| # is well documented it seems to be used in error quite often. To avoid | |
| # problems we disallow the direct use of memcpy. The exceptions are in | |
| # third-party code and in platform/globals.h which uses it to implement | |
| # bit_cast and bit_copy. | |
| # pthread_detach (and therefore std::thread::detach) have a bug that can | |
| # result in crashes. https://sourceware.org/bugzilla/show_bug.cgi?id=19951 | |
| BANNED_FUNCTIONS = [ | |
| ['\\bmemcpy\\(', 'memcpy'], | |
| ['\\bpthread_detach\\(', 'pthread_detach'], | |
| ] | |
| def CheckBannedFunctions(filename): | |
| if filename.endswith(os.path.join('platform', 'globals.h')) or \ | |
| filename.find('third_party') != -1: | |
| return 0 | |
| fh = open(filename, 'r') | |
| content = fh.read() | |
| for banned_function in BANNED_FUNCTIONS: | |
| pattern = banned_function[0] | |
| name = banned_function[1] | |
| match = re.search(pattern, content) | |
| if match: | |
| offset = match.start() | |
| end_of_line = content.index('\n', offset) | |
| # We allow explicit use of memcpy with an opt-in via NOLINT | |
| if 'NOLINT' not in content[offset:end_of_line]: | |
| line_number = content[0:match.start()].count('\n') + 1 | |
| print("%s:%d: use of %s is forbidden" % | |
| (filename, line_number, name)) | |
| return 1 | |
| return 0 | |
| def RunLint(input_api, output_api): | |
| result = [] | |
| cpplint._cpplint_state.ResetErrorCounts() | |
| banned_match_count = 0 | |
| # Find all .cc and .h files in the change list. | |
| for git_file in input_api.AffectedTextFiles(): | |
| filename = git_file.AbsoluteLocalPath() | |
| # Don't lint V8 sources. | |
| if 'runtime/vm/regexp/' in filename: | |
| continue | |
| if filename.endswith('.cc') or ( | |
| # cpplint complains about the style of #ifndefs in our .pbzero.h | |
| # files, but they are generated by the protozero compiler, so we | |
| # can't fix this. | |
| not filename.endswith('.pbzero.h') and filename.endswith('.h')): | |
| # Run cpplint on the file. | |
| cpplint.ProcessFile(filename, 1) | |
| # Check for memcpy use. | |
| banned_match_count += CheckBannedFunctions(filename) | |
| # Report a presubmit error if any of the files had an error. | |
| if cpplint._cpplint_state.error_count > 0 or banned_match_count > 0: | |
| result = [output_api.PresubmitError('Failed cpplint check.')] | |
| return result | |
| def CheckGn(input_api, output_api): | |
| return input_api.canned_checks.CheckGNFormatted(input_api, output_api) | |
| def CheckFormatted(input_api, output_api): | |
| def convert_warning_to_error(presubmit_result): | |
| if not presubmit_result.fatal: | |
| # Convert this warning to an error. | |
| result_json = presubmit_result.json_format() | |
| return output_api.PresubmitError( | |
| message=result_json['message'], | |
| items=result_json['items'], | |
| long_text=result_json['long_text']) | |
| return presubmit_result | |
| results = input_api.canned_checks.CheckPatchFormatted(input_api, output_api) | |
| return [convert_warning_to_error(r) for r in results] | |
| def CheckChangeOnUpload(input_api, output_api): | |
| return (RunLint(input_api, output_api) + CheckGn(input_api, output_api) + | |
| CheckFormatted(input_api, output_api)) | |
| def CheckChangeOnCommit(input_api, output_api): | |
| return (RunLint(input_api, output_api) + CheckGn(input_api, output_api) + | |
| CheckFormatted(input_api, output_api)) |