Static Initializers
[TOC]
Some background on the original decision to ban static initializers:
http://neugierig.org/software/chromium/notes/2011/08/static-initializers.html
Note: Another name for static initializers is "global constructors".
How Static Initializers are Checked
- For Linux and Mac:
- The expected count is stored in //testing/scripts/check_static_initializers.py
- For Android:
- The expected count is stored in //chrome/android/static_initializers.gni
Removing Static Initializers
Common fixes include:
- Add constexpr.
- Move global variable to be a static variable within a function that returns
it, often wrapped in
base::NoDestructor.
Listing Static Initializers
Option 1 - dump-static-initializers.py
For Linux:
tools/linux/dump-static-initializers.py out/Release/chrome
For Android:
# Build with: is_official_build=true is_chrome_branded=true
# This will dump the list of SI's only when they don't match the expected
# number in static_initializers.gni (this is what the bots use).
ninja chrome/android:monochrome_static_initializers
# or, to dump directly:
tools/linux/dump-static-initializers.py out/Release/lib.unstripped/libmonochrome.so
Option 2 - Ask compiler to report them
If the source of the new initializers is not obvious from Step 1, you can ask the compiler to pinpoint the exact source line.
- Edit //build/config/BUILDCONFIG.gn
and add
"//build/config/compiler:wglobal_constructors"todefault_compiler_configs - Remove the config from the
configsin//base:base - Set GN arg
treat_warnings_as_errors=false - Compile and look for warnings from the files identified by step 1 (may want to pipe ninja output to a file).
*** note The compiler warning triggers for every static initializer that exists before optimization. We care only about those that survive optimization. More details in crbug/1136086.
- For more information about
diagnose_bloat.py, refer to its README.md - List of existing static initializers documented in static_initializers.gni
Option 3 - Manual Verification
You can manually go through the steps that dump-static-initializers.py does.
- Locate the address range of the .init_array section with:
$ third_party/llvm-build/Release+Asserts/bin/llvm-readelf \
--hex-dump=.init_array out/Release/lib.unstripped/libmonochrome.so
Hex dump of section '.init_array':
0x04064624 294a1a02 154acb00 79d3be01 894c1a02 )J...J..y....L..
0x04064624is the location of.init_array.- The other four entries are addresses of functions in little endian.
- Convert the address into a function name with:
# Reverse hex pairs to account for endianness.
$ third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer \
--functions -e out/Release/lib.unstripped/libmonochrome.so 0x021a4a29
_GLOBAL__I_000101
./../../buildtools/third_party/libc++/trunk/src/iostream.cpp:0:0
- If any
.init_arrayslots are zero, that means they their address is exists within the relocation table. To find the address:
# Use the location of ".init_array" printed in step 1, plus an offset for subsequent slots.
$ third_party/llvm-build/Release+Asserts/bin/llvm-readelf \
--relocations out/Release/lib.unstripped/libmonochrome.so | grep 0x04064624
03dfb7b0 00000017 R_ARM_RELATIVE 0