| #!/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() | 
 |         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)) |