Commit a1ad0ec3 authored by Yuke Liao's avatar Yuke Liao Committed by Commit Bot

Use whitelist to check static initializers

This CL does two things:
1. Replace the SI count check with a whitelist check.
2. Add InstrProfilingRuntime.cc to the whitelist because coverage build
   needs it and it is ONLY used on coverage build.

This change only applies to Linux platform, and in order to make Mac
platform work, a separate CL is required to change
//tools/mac/dump-static-initializers.py to have the same output format
as //tools/linux/dump-static-initializers.py.

Bug: 956591
Change-Id: I54119676bea59a8f1e6fdba470bbeac32b121c3c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1653319Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Commit-Queue: Yuke Liao <liaoyuke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#668535}
parent 56a2fd94
...@@ -11,14 +11,25 @@ import sys ...@@ -11,14 +11,25 @@ import sys
import common import common
# If something adds a static initializer, revert it, don't increase these # A list of whitelisted files that are allowed to have static initializers.
# numbers. We don't accept regressions in static initializers. # If something adds a static initializer, revert it. We don't accept regressions
EXPECTED_LINUX_SI_COUNTS = { # in static initializers.
'chrome': 4, _LINUX_SI_FILE_WHITELIST = {
'nacl_helper': 4, 'chrome': [
'nacl_helper_bootstrap': 0, 'InstrProfilingRuntime.cc', # Only in coverage builds, not production.
'atomicops_internals_x86.cc', # TODO(crbug.com/973551): Remove.
'debugallocation_shim.cc', # TODO(crbug.com/973552): Remove.
'iostream.cpp', # TODO(crbug.com/973554): Remove.
'spinlock.cc', # TODO(crbug.com/973556): Remove.
],
'nacl_helper_bootstrap': [],
} }
_LINUX_SI_FILE_WHITELIST['nacl_helper'] = _LINUX_SI_FILE_WHITELIST['chrome']
# TODO: Convert Mac to use the whitelist, but need to first modify
# //tools/mac/dump-static-initializers.py to have the same stdout format as
# //tools/linux/dump-static-initializers.py.
#
# A static initializer is needed on Mac for libc++ to set up std::cin/cout/cerr # A static initializer is needed on Mac for libc++ to set up std::cin/cout/cerr
# before main() runs. # before main() runs.
EXPECTED_MAC_SI_COUNT = 1 EXPECTED_MAC_SI_COUNT = 1
...@@ -92,56 +103,39 @@ def main_mac(src_dir): ...@@ -92,56 +103,39 @@ def main_mac(src_dir):
def main_linux(src_dir): def main_linux(src_dir):
def get_elf_section_size(readelf_stdout, section_name):
# Matches: .ctors PROGBITS 000000000516add0 5169dd0 000010 00 WA 0 0 8
match = re.search(r'\.%s.*$' % re.escape(section_name), readelf_stdout,
re.MULTILINE)
if not match:
return (False, -1)
size_str = re.split(r'\W+', match.group(0))[5]
return (True, int(size_str, 16))
def get_word_size(binary_name):
stdout = run_process(['readelf', '-h', binary_name])
elf_class_line = re.search('Class:.*$', stdout, re.MULTILINE).group(0)
elf_class = re.split(r'\W+', elf_class_line)[1]
if elf_class == 'ELF32':
return 4
elif elf_class == 'ELF64':
return 8
raise Exception('Unsupported architecture')
ret = 0 ret = 0
for binary_name in EXPECTED_LINUX_SI_COUNTS: for binary_name in _LINUX_SI_FILE_WHITELIST:
if not os.path.exists(binary_name): if not os.path.exists(binary_name):
continue continue
# NOTE: this is very implementation-specific and makes assumptions
# about how compiler and linker implement global static initializers. dump_static_initializers = os.path.join(src_dir, 'tools', 'linux',
si_count = 0 'dump-static-initializers.py')
stdout = run_process(['readelf', '-SW', binary_name]) stdout = run_process([dump_static_initializers, '-d', binary_name])
has_init_array, init_array_size = get_elf_section_size(stdout, 'init_array') # The output has the following format:
if has_init_array: # First lines: '# <file_name> <si_name>'
si_count = init_array_size / get_word_size(binary_name) # Last line: '# Found <num> static initializers in <num> files.'
# In newer versions of gcc crtbegin.o inserts frame_dummy into .init_array #
# but we don't want to count this entry, since its always present and not # For example:
# related to our code. # # spinlock.cc GetSystemCPUsCount()
stdout = run_process(['objdump', '-t', binary_name, '-j' '.init_array']) # # spinlock.cc adaptive_spin_count
if '__frame_dummy_init_array_entry' in stdout: # # Found 2 static initializers in 1 files.
si_count -= 1
files_with_si = set()
# Print the list of static initializers. for line in stdout.splitlines()[:-1]:
if (binary_name in EXPECTED_LINUX_SI_COUNTS and parts = line.split(' ', 2)
si_count > EXPECTED_LINUX_SI_COUNTS[binary_name]): assert len(parts) == 3 and parts[0] == '#'
print('Expected <= %d static initializers in %s, but found %d' %
(EXPECTED_LINUX_SI_COUNTS[binary_name], binary_name, si_count)) files_with_si.add(parts[1])
ret = 1
if si_count > 0: for f in files_with_si:
dump_static_initializers = os.path.join(src_dir, 'tools', 'linux', if f not in _LINUX_SI_FILE_WHITELIST[binary_name]:
'dump-static-initializers.py') ret = 1
stdout = run_process([dump_static_initializers, '-d', binary_name]) print('Error: file "%s" is not expected to have static initializers in'
print '\n# Static initializers in %s:' % binary_name ' binary "%s"') % (f, binary_name)
print stdout
print '\n# Static initializers in %s:' % binary_name
print stdout
return ret return ret
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment