<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Pythran stories - mozilla</title><link href="http://serge-sans-paille.github.io/pythran-stories/" rel="alternate"></link><link href="http://serge-sans-paille.github.io/pythran-stories/feeds/mozilla.atom.xml" rel="self"></link><id>http://serge-sans-paille.github.io/pythran-stories/</id><updated>2025-05-29T00:00:00+02:00</updated><entry><title>A Hidden Weakness</title><link href="http://serge-sans-paille.github.io/pythran-stories/a-hidden-weakness.html" rel="alternate"></link><published>2025-05-29T00:00:00+02:00</published><updated>2025-05-29T00:00:00+02:00</updated><author><name>serge-sans-paille</name></author><id>tag:serge-sans-paille.github.io,2025-05-29:/pythran-stories/a-hidden-weakness.html</id><summary type="html">&lt;p class="first last"&gt;A surprising combination of symbol qualifiers that lead to a long bug hunt.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This is the story of a bug hunt that lasted much longer than expected, but ended
with the dearest of all treasures: &lt;em&gt;knowledge&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Let's draw some context: the Android platform defines different API levels.
Unsurprisingly, some symbols are only defined starting with a given API version.
For instance, &lt;tt class="docutils literal"&gt;ASystemFontIterator_open&lt;/tt&gt; is only available starting at API 29.&lt;/p&gt;
&lt;p&gt;Unconditionally trying to use &lt;tt class="docutils literal"&gt;ASystemFontIterator_open&lt;/tt&gt; while targeting an
API older than 29 leads to a linker error (an undefined reference), which makes
sense because the symbol, well, does not exist at that API level.&lt;/p&gt;
&lt;p&gt;So a native application that wants to use this symbol can either refuse to run on
older API, or use a combination of &lt;tt class="docutils literal"&gt;dlopen&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;dlsym&lt;/tt&gt; to dynamically
lookup for the symbol and provide a fallback if it does not exist. The latter
approach is used on Fenix, the Android version of Firefox.&lt;/p&gt;
&lt;div class="section" id="introducing-android-unavailable-symbols-are-weak"&gt;
&lt;h2&gt;Introducing &lt;tt class="docutils literal"&gt;__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__&lt;/tt&gt;&lt;/h2&gt;
&lt;p&gt;As an alternative to the features from &lt;tt class="docutils literal"&gt;&amp;lt;dlfcn.h&amp;gt;&lt;/tt&gt;, Android build system makes
it possible to define &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__&lt;/span&gt;&lt;/tt&gt;, combine it
with a compiler check through &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Werror=unguarded-availability&lt;/span&gt;&lt;/tt&gt; and a runtime
check through &lt;tt class="docutils literal"&gt;__builtin_available&lt;/tt&gt;. Here is an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// The header that defines ASystemFontIterator_open.&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;android/system_fonts.h&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;// Runtime check for API level&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__builtin_available&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Reference to the actual symbol. Does not fail at link time because an&lt;/span&gt;
&lt;span class="cm"&gt;       alternative weak definition is always provided by &amp;lt;android/system_fonts.h&amp;gt;*/&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ASystemFontIterator_open&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There's a lot happening there, so let's dive in the wilderness of compiler
extensions.&lt;/p&gt;
&lt;div class="section" id="android-system-fonts-h"&gt;
&lt;h3&gt;&lt;tt class="docutils literal"&gt;&amp;lt;android/system_fonts.h&amp;gt;&lt;/tt&gt;&lt;/h3&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;ASystemFontIterator_open&lt;/tt&gt; is defined in &lt;tt class="docutils literal"&gt;&amp;lt;android/system_fonts.h&amp;gt;&lt;/tt&gt; as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;ASystemFontIterator&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Nullable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ASystemFontIterator_open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;__INTRODUCED_IN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;_Nullable&lt;/tt&gt; attribute is an interesting topic, but it's a side quest we're
not going to explore today. The macro function &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__INTRODUCED_IN(...)&lt;/span&gt;&lt;/tt&gt; is
defined in &lt;tt class="docutils literal"&gt;&amp;lt;android/versioning.h&amp;gt;&lt;/tt&gt; as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#define __INTRODUCED_IN(api_level) __BIONIC_AVAILABILITY(introduced=api_level)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And &lt;tt class="docutils literal"&gt;__BIONIC_AVAILABILITY&lt;/tt&gt; is conditionally defined in the same header as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;#define __BIONIC_AVAILABILITY(__what, ...) __attribute__((__availability__(android,__what __VA_OPT__(,) __VA_ARGS__)))&lt;/span&gt;
&lt;span class="cp"&gt;#else&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;#define __BIONIC_AVAILABILITY(__what, ...) __attribute__((__availability__(android,strict,__what __VA_OPT__(,) __VA_ARGS__)))&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So in our case &lt;tt class="docutils literal"&gt;ASystemFontIterator_open&lt;/tt&gt; is flagged either with
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__attribute__((__availability__(android,introduced=29))&lt;/span&gt;&lt;/tt&gt; or
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__attribute__((__availability__(android,strict,introduced=29))&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Let's write a simple C code containing only the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;a.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt; EOF&lt;/span&gt;
&lt;span class="s"&gt;void foo(void) __attribute__((__availability__(android,introduced=29)));&lt;/span&gt;
&lt;span class="s"&gt;void bar(void) __attribute__((__availability__(android,strict,introduced=29)));&lt;/span&gt;
&lt;span class="s"&gt;void foobar(void) {&lt;/span&gt;
&lt;span class="s"&gt;  foo();&lt;/span&gt;
&lt;span class="s"&gt;  bar();&lt;/span&gt;
&lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compile and inspect it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-linux-android21&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;a.c
a.c:5:3:&lt;span class="w"&gt; &lt;/span&gt;error:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;unavailable:&lt;span class="w"&gt; &lt;/span&gt;introduced&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Android&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;android
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;bar&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;^
a.c:2:6:&lt;span class="w"&gt; &lt;/span&gt;note:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;has&lt;span class="w"&gt; &lt;/span&gt;been&lt;span class="w"&gt; &lt;/span&gt;explicitly&lt;span class="w"&gt; &lt;/span&gt;marked&lt;span class="w"&gt; &lt;/span&gt;unavailable&lt;span class="w"&gt; &lt;/span&gt;here
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;void&lt;span class="w"&gt; &lt;/span&gt;bar&lt;span class="o"&gt;(&lt;/span&gt;void&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;__attribute__&lt;span class="o"&gt;((&lt;/span&gt;__availability__&lt;span class="o"&gt;(&lt;/span&gt;android,strict,introduced&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;^
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;generated.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ok, so the &lt;tt class="docutils literal"&gt;strict&lt;/tt&gt; keyword implies a compilation error if we reference that
symbol while targeting a lower version. Good. Let's remove it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;b.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt; EOF&lt;/span&gt;
&lt;span class="s"&gt;void foo(void) __attribute__((__availability__(android,introduced=29)));&lt;/span&gt;
&lt;span class="s"&gt;void foobar(void) {&lt;/span&gt;
&lt;span class="s"&gt;  foo();&lt;/span&gt;
&lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-linux-android21&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;b.c
$&lt;span class="w"&gt; &lt;/span&gt;nm&lt;span class="w"&gt; &lt;/span&gt;b.o
&lt;span class="w"&gt;                 &lt;/span&gt;w&lt;span class="w"&gt; &lt;/span&gt;foo
&lt;span class="m"&gt;0000000000000000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;T&lt;span class="w"&gt; &lt;/span&gt;foobar
$&lt;span class="w"&gt; &lt;/span&gt;readelf&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;b.o

Symbol&lt;span class="w"&gt; &lt;/span&gt;table&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.symtab&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;entries:
&lt;span class="w"&gt;   &lt;/span&gt;Num:&lt;span class="w"&gt;    &lt;/span&gt;Value&lt;span class="w"&gt;          &lt;/span&gt;Size&lt;span class="w"&gt; &lt;/span&gt;Type&lt;span class="w"&gt;    &lt;/span&gt;Bind&lt;span class="w"&gt;   &lt;/span&gt;Vis&lt;span class="w"&gt;      &lt;/span&gt;Ndx&lt;span class="w"&gt; &lt;/span&gt;Name
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0000000000000000&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;NOTYPE&lt;span class="w"&gt;  &lt;/span&gt;LOCAL&lt;span class="w"&gt;  &lt;/span&gt;DEFAULT&lt;span class="w"&gt;  &lt;/span&gt;UND
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0000000000000000&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;FILE&lt;span class="w"&gt;    &lt;/span&gt;LOCAL&lt;span class="w"&gt;  &lt;/span&gt;DEFAULT&lt;span class="w"&gt;  &lt;/span&gt;ABS&lt;span class="w"&gt; &lt;/span&gt;b.c
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0000000000000000&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;SECTION&lt;span class="w"&gt; &lt;/span&gt;LOCAL&lt;span class="w"&gt;  &lt;/span&gt;DEFAULT&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;.text
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0000000000000000&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;FUNC&lt;span class="w"&gt;    &lt;/span&gt;GLOBAL&lt;span class="w"&gt; &lt;/span&gt;DEFAULT&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;foobar
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0000000000000000&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;NOTYPE&lt;span class="w"&gt;  &lt;/span&gt;WEAK&lt;span class="w"&gt;   &lt;/span&gt;DEFAULT&lt;span class="w"&gt;  &lt;/span&gt;UND&lt;span class="w"&gt; &lt;/span&gt;foo
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;No compilation error, even though the symbol &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; is marked as available only
for more recent API. Instead we end up with a symbol &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; marked as &lt;tt class="docutils literal"&gt;WEAK&lt;/tt&gt;
(&lt;tt class="docutils literal"&gt;w&lt;/tt&gt;) and &lt;tt class="docutils literal"&gt;UND&lt;/tt&gt; (for undefined). Calling this symbol is equivalent to
dereferencing a &lt;tt class="docutils literal"&gt;nullptr&lt;/tt&gt; and ends up with a segfault. Not super safe!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="werror-unguarded-availability"&gt;
&lt;h3&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Werror=unguarded-availability&lt;/span&gt;&lt;/tt&gt;&lt;/h3&gt;
&lt;p&gt;Fortunately, Clang provides a dedicated warning &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Wungarded-availability&lt;/span&gt;&lt;/tt&gt;,
turned into an error through &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Werror=unguarded-availability&lt;/span&gt;&lt;/tt&gt;. This flag
enables static checking for calls that would resolve into calling undefined weak
reference because of an &lt;tt class="docutils literal"&gt;__availability__&lt;/tt&gt; mismatch.&lt;/p&gt;
&lt;p&gt;Indeed in our case:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-linux-android21&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;b.c&lt;span class="w"&gt; &lt;/span&gt;-Werror&lt;span class="o"&gt;=&lt;/span&gt;unguarded-availability
b.c:3:3:&lt;span class="w"&gt; &lt;/span&gt;error:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;only&lt;span class="w"&gt; &lt;/span&gt;available&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;Android&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;newer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-Werror,-Wunguarded-availability&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;foo&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;^~~
b.c:1:6:&lt;span class="w"&gt; &lt;/span&gt;note:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;has&lt;span class="w"&gt; &lt;/span&gt;been&lt;span class="w"&gt; &lt;/span&gt;marked&lt;span class="w"&gt; &lt;/span&gt;as&lt;span class="w"&gt; &lt;/span&gt;being&lt;span class="w"&gt; &lt;/span&gt;introduced&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Android&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;here,&lt;span class="w"&gt; &lt;/span&gt;but&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;deployment&lt;span class="w"&gt; &lt;/span&gt;target&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;Android&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;21&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;void&lt;span class="w"&gt; &lt;/span&gt;foo&lt;span class="o"&gt;(&lt;/span&gt;void&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;__attribute__&lt;span class="o"&gt;((&lt;/span&gt;__availability__&lt;span class="o"&gt;(&lt;/span&gt;android,introduced&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;^
b.c:3:3:&lt;span class="w"&gt; &lt;/span&gt;note:&lt;span class="w"&gt; &lt;/span&gt;enclose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;__builtin_available&lt;span class="w"&gt; &lt;/span&gt;check&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;silence&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;warning
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;foo&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;^~~
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;generated.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's follow the compiler hint and guard our execution:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;c.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt; EOF&lt;/span&gt;
&lt;span class="s"&gt;void foo(void) __attribute__((__availability__(android,introduced=29)));&lt;/span&gt;
&lt;span class="s"&gt;void foobar(void) {&lt;/span&gt;
&lt;span class="s"&gt;  if (__builtin_available(android 29, *))&lt;/span&gt;
&lt;span class="s"&gt;    foo();&lt;/span&gt;
&lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-linux-android21&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;c.c&lt;span class="w"&gt; &lt;/span&gt;-Werror&lt;span class="o"&gt;=&lt;/span&gt;unguarded-availability
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;No error, and indeed a guard is generated, as shown by the intermediate compiler
representation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-linux-android21&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;-emit-llvm&lt;span class="w"&gt; &lt;/span&gt;c.c&lt;span class="w"&gt; &lt;/span&gt;-Werror&lt;span class="o"&gt;=&lt;/span&gt;unguarded-availability
...
define&lt;span class="w"&gt; &lt;/span&gt;dso_local&lt;span class="w"&gt; &lt;/span&gt;void&lt;span class="w"&gt; &lt;/span&gt;@foobar&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0 {&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;%1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;call&lt;span class="w"&gt; &lt;/span&gt;i32&lt;span class="w"&gt; &lt;/span&gt;@__isOSVersionAtLeast&lt;span class="o"&gt;(&lt;/span&gt;i32&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;i32&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;i32&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#2&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;%2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;icmp&lt;span class="w"&gt; &lt;/span&gt;ne&lt;span class="w"&gt; &lt;/span&gt;i32&lt;span class="w"&gt; &lt;/span&gt;%1,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;br&lt;span class="w"&gt; &lt;/span&gt;i1&lt;span class="w"&gt; &lt;/span&gt;%2,&lt;span class="w"&gt; &lt;/span&gt;label&lt;span class="w"&gt; &lt;/span&gt;%3,&lt;span class="w"&gt; &lt;/span&gt;label&lt;span class="w"&gt; &lt;/span&gt;%4

&lt;span class="m"&gt;3&lt;/span&gt;:&lt;span class="w"&gt;                                                &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;preds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%0
&lt;span class="w"&gt;  &lt;/span&gt;call&lt;span class="w"&gt; &lt;/span&gt;void&lt;span class="w"&gt; &lt;/span&gt;@foo&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;br&lt;span class="w"&gt; &lt;/span&gt;label&lt;span class="w"&gt; &lt;/span&gt;%4

&lt;span class="m"&gt;4&lt;/span&gt;:&lt;span class="w"&gt;                                                &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;preds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%3,&lt;span class="w"&gt; &lt;/span&gt;%0
&lt;span class="w"&gt;  &lt;/span&gt;ret&lt;span class="w"&gt; &lt;/span&gt;void
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The function &lt;tt class="docutils literal"&gt;__isOSVersionAtLeast&lt;/tt&gt; is part of the compiler runtime and its
implementation performs a costly check at first call, memoize the result and
then just reads the memoized result, which is quite fast.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="the-actual-quest"&gt;
&lt;h2&gt;The Actual Quest&lt;/h2&gt;
&lt;p&gt;This was a long detour before we reach our archenemy: the Firefox build system.
In a situation similar to the one described above, we indeed end up with a weak
symbol for &lt;tt class="docutils literal"&gt;ASystemFontIterator_open&lt;/tt&gt; in the object file, but when creating a
shared library, the symbol is just marked as undefined, and on system with
recent API, the &lt;tt class="docutils literal"&gt;__isOSVersionAtLeast&lt;/tt&gt; check passes but the guarded symbol is
undefined and everything went kaboom.&lt;/p&gt;
&lt;p&gt;I'll spare you the detail I took to verify that the &lt;tt class="docutils literal"&gt;libandroid.so&lt;/tt&gt; we use is
the right one, it has the right symbol which should supersedes the weak definition
of &lt;tt class="docutils literal"&gt;ASystemFontIterator_open&lt;/tt&gt; if it were marked as weak, but because it's
marked undefined, it's just not there. Why would that happen?&lt;/p&gt;
&lt;p&gt;Then I carefully compared the symbols between my object file from the Firefox
build system, and the one from my minimal reproducer above. And I ended up with
these two lines:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
0000000000000000     0 NOTYPE  WEAK   HIDDEN   UND ASystemFontIterator_open

0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND foo
&lt;/pre&gt;
&lt;p&gt;They look the same. But, wait, &lt;tt class="docutils literal"&gt;HIDDEN&lt;/tt&gt;? Why would,
&lt;tt class="docutils literal"&gt;ASystemFontIterator_open&lt;/tt&gt;, a symbol that comes from a system header, be
marked as &lt;tt class="docutils literal"&gt;HIDDEN&lt;/tt&gt;? I quickly double-checked and there was no
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fvisibility=hidden&lt;/span&gt;&lt;/tt&gt; on the compiler invocation.&lt;/p&gt;
&lt;p&gt;But there was something else.&lt;/p&gt;
&lt;p&gt;A simple flag that looked innocent.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-include&lt;/span&gt; config/gcc_hidden.h&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;And in that very single file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;config/gcc_hidden.h
/*&lt;span class="w"&gt; &lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;Source&lt;span class="w"&gt; &lt;/span&gt;Code&lt;span class="w"&gt; &lt;/span&gt;Form&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;subject&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;terms&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;Mozilla&lt;span class="w"&gt; &lt;/span&gt;Public
&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;License,&lt;span class="w"&gt; &lt;/span&gt;v.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0.&lt;span class="w"&gt; &lt;/span&gt;If&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;copy&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;MPL&lt;span class="w"&gt; &lt;/span&gt;was&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;distributed&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;this
&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;file,&lt;span class="w"&gt; &lt;/span&gt;You&lt;span class="w"&gt; &lt;/span&gt;can&lt;span class="w"&gt; &lt;/span&gt;obtain&lt;span class="w"&gt; &lt;/span&gt;one&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;http://mozilla.org/MPL/2.0/.&lt;span class="w"&gt; &lt;/span&gt;*/

/*&lt;span class="w"&gt; &lt;/span&gt;Begin&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;files&lt;span class="w"&gt; &lt;/span&gt;as&lt;span class="w"&gt; &lt;/span&gt;hidden&lt;span class="w"&gt; &lt;/span&gt;visibility&lt;span class="w"&gt; &lt;/span&gt;*/
&lt;span class="c1"&gt;#pragma GCC visibility push(hidden)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Et voilà&lt;/em&gt;, Firefox defaults to building with hidden visibility, this impacts
the weak symbols generated as a consequence of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__attribute__((__availability__(android,introduced=29)))&lt;/span&gt;&lt;/tt&gt; and we can indeed reproduce the issue:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;d.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt; EOF&lt;/span&gt;
&lt;span class="s"&gt;#pragma GCC visibility push(hidden)&lt;/span&gt;
&lt;span class="s"&gt;void foo(void) __attribute__((__availability__(android,introduced=29)));&lt;/span&gt;
&lt;span class="s"&gt;void foobar(void) {&lt;/span&gt;
&lt;span class="s"&gt;  foo();&lt;/span&gt;
&lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;--target&lt;span class="o"&gt;=&lt;/span&gt;x86_64-linux-android21&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;d.c
$&lt;span class="w"&gt; &lt;/span&gt;readelf&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;d.o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-E&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\&amp;lt;foo\&amp;gt;&amp;#39;&lt;/span&gt;
&lt;span class="m"&gt;4&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0000000000000000&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;NOTYPE&lt;span class="w"&gt;  &lt;/span&gt;WEAK&lt;span class="w"&gt;   &lt;/span&gt;HIDDEN&lt;span class="w"&gt;   &lt;/span&gt;UND&lt;span class="w"&gt; &lt;/span&gt;foo
$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;-shared&lt;span class="w"&gt; &lt;/span&gt;d.o&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;libfoo.so
$&lt;span class="w"&gt; &lt;/span&gt;nm&lt;span class="w"&gt; &lt;/span&gt;libfoo.so&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-E&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\&amp;lt;foo\&amp;gt;&amp;#39;&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;libfoo.so
...
&lt;span class="m"&gt;0000000000000320&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;foobar&amp;gt;:
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;320&lt;/span&gt;:&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rbp
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;321&lt;/span&gt;:&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e5&lt;span class="w"&gt;                &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;%rsp,%rbp
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;324&lt;/span&gt;:&lt;span class="w"&gt;        &lt;/span&gt;e8&lt;span class="w"&gt; &lt;/span&gt;d7&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;fc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt;          &lt;/span&gt;call&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;_init-0x224&amp;gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;329&lt;/span&gt;:&lt;span class="w"&gt;        &lt;/span&gt;5d&lt;span class="w"&gt;                      &lt;/span&gt;pop&lt;span class="w"&gt;    &lt;/span&gt;%rbp
&lt;span class="w"&gt; &lt;/span&gt;32a:&lt;span class="w"&gt;        &lt;/span&gt;c3&lt;span class="w"&gt;                      &lt;/span&gt;ret
...
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;the call to &lt;tt class="docutils literal"&gt;foo&lt;/tt&gt; got turned into a call to &lt;tt class="docutils literal"&gt;0&lt;/tt&gt;. Even on more recent
platforms, a &lt;tt class="docutils literal"&gt;0&lt;/tt&gt; stays a &lt;tt class="docutils literal"&gt;0&lt;/tt&gt;, the weak reference trick no longer works.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-fix"&gt;
&lt;h2&gt;The Fix&lt;/h2&gt;
&lt;p&gt;As usual, the fix is very small, compared to the amount of work required to find
it. In our case we can temporarily change the default visibility when including
android system headers, as in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#pragma GCC visibility push(default)&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;android/system_fonts.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#pragma GCC visibility pop&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As it's often the case, the journey is the real reward. But getting &lt;a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1966309"&gt;Bug 1966309&lt;/a&gt;
fixed is also not bad ;-)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="acknowledgments"&gt;
&lt;h2&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;Thanks goes to Olivia Hall for providing initial help with Android platform
details.&lt;/p&gt;
&lt;/div&gt;
</content><category term="mozilla"></category></entry><entry><title>Trivial Auto Var Init Experiments</title><link href="http://serge-sans-paille.github.io/pythran-stories/trivial-auto-var-init-experiments.html" rel="alternate"></link><published>2023-12-19T00:00:00+01:00</published><updated>2023-12-19T00:00:00+01:00</updated><author><name>serge-sans-paille</name></author><id>tag:serge-sans-paille.github.io,2023-12-19:/pythran-stories/trivial-auto-var-init-experiments.html</id><summary type="html">&lt;p class="first last"&gt;exploring the impact of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init&lt;/span&gt;&lt;/tt&gt; on Firefox codebase&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init=[pattern|zero|uninitialized]&lt;/span&gt;&lt;/tt&gt; is a compiler flag that controls how the stack is initialized before any value is initialized to it. The default is &lt;tt class="docutils literal"&gt;uninitialized&lt;/tt&gt;: no initialisation is done, reading from an uninitialized location of the stack yields whatever value lies there at that point. This is Undefined Behavior in both C and C++. It makes stack allocation a &lt;span class="formula"&gt;&lt;span class="scriptfont"&gt;O&lt;/span&gt;(1)&lt;/span&gt; operation, which is nice, but it also is (a) a common source of programming errors (b) a potential security issue.&lt;/p&gt;
&lt;p&gt;As a countermeasure, the modes &lt;tt class="docutils literal"&gt;pattern&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;zero&lt;/tt&gt; have been introduced.
The former sets stack slots to hard-coded patterns, depending on the type
(integral, floating point, pointer…) of the associated stack-allocated
variables, the latter justs sets the stack to zero. Both operation make stack
allocation a  &lt;span class="formula"&gt;&lt;span class="scriptfont"&gt;O&lt;/span&gt;(&lt;i&gt;n&lt;/i&gt;)&lt;/span&gt; operation. The idea between the two modes is that
setting stack slots to zero is faster, but setting them to a pattern is more
likely to exhibit failing behavior.&lt;/p&gt;
&lt;div class="section" id="comparing-the-approach-with-address-sanitizer"&gt;
&lt;h2&gt;Comparing the Approach with Address Sanitizer&lt;/h2&gt;
&lt;p&gt;Let's consider a very simple program that reads data from &lt;tt class="docutils literal"&gt;stdin&lt;/tt&gt; and dumps it to
&lt;tt class="docutils literal"&gt;stdout&lt;/tt&gt;, using a small buffer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When compiled with &lt;tt class="docutils literal"&gt;clang &lt;span class="pre"&gt;-O2&lt;/span&gt; &lt;span class="pre"&gt;-S&lt;/span&gt; &lt;span class="pre"&gt;-emit-llvm&lt;/span&gt; &lt;span class="pre"&gt;-o-&lt;/span&gt;&lt;/tt&gt; the function entry block,
expressed in LLVM IR, is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.lifetime.start.p0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#3&lt;/span&gt;
&lt;span class="k"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first instruction allocates memory on the stack, and that's it.&lt;/p&gt;
&lt;p&gt;If we compile it with &lt;tt class="docutils literal"&gt;clang &lt;span class="pre"&gt;-O2&lt;/span&gt; &lt;span class="pre"&gt;-S&lt;/span&gt; &lt;span class="pre"&gt;-emit-llvm&lt;/span&gt; &lt;span class="pre"&gt;-o-&lt;/span&gt; &lt;span class="pre"&gt;-ftrivial-auto-var-init=zero&lt;/span&gt;&lt;/tt&gt;, the prologue becomes (note the extra &lt;tt class="docutils literal"&gt;llvm.memset&lt;/tt&gt; to zero):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.lifetime.start.p0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#4&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.memset.p0.i64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;!annotation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!3&lt;/span&gt;
&lt;span class="k"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When passing &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init=pattern&lt;/span&gt;&lt;/tt&gt; we keep the &lt;tt class="docutils literal"&gt;llvm.memset&lt;/tt&gt;,
but zero has been turned into a pattern (&lt;tt class="docutils literal"&gt;0xAA&lt;/tt&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.lifetime.start.p0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#4&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.memset.p0.i64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;-86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;!annotation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!3&lt;/span&gt;
&lt;span class="k"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In both cases, the &lt;tt class="docutils literal"&gt;llvm.memset&lt;/tt&gt; call is annotated with some metadata that
help tracking its origin.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!{&lt;/span&gt;&lt;span class="nv"&gt;!&amp;quot;auto-init&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The call to &lt;tt class="docutils literal"&gt;llvm.memset&lt;/tt&gt; is directly followed by a call to &lt;tt class="docutils literal"&gt;fread&lt;/tt&gt; that may
only partially write the buffer, so there is no way for the compiler to get rid
of it, even if the subsequent &lt;tt class="docutils literal"&gt;fwrite&lt;/tt&gt; will never access uninitialized slots.&lt;/p&gt;
&lt;p&gt;An important point is that on that particular code,
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init=zero/default&lt;/span&gt;&lt;/tt&gt; doesn't have any other impact on the
code. In particular no memory read or write is being instrumented.&lt;/p&gt;
&lt;p&gt;By contrast, using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fsanitize=memory&lt;/span&gt;&lt;/tt&gt; leads to the following function
prologue, that contains both a &lt;tt class="docutils literal"&gt;memset&lt;/tt&gt; of the whole buffer and the &lt;em&gt;xoring&lt;/em&gt; of
every loaded address with 87960930222080 (actually &lt;tt class="docutils literal"&gt;0x500000000000&lt;/tt&gt;). So it's
strictly slower, especially as it impacts elements of the inner loop (whenever
&lt;tt class="docutils literal"&gt;stdout&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;stdin&lt;/tt&gt; are loaded in memory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;%buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.lifetime.start.p0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#5&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ptrtoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%buffer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;87960930222080&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;inttoptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.memset.p0.i64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;%_msld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;inttoptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;xor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ptrtoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@stdin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;87960930222080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;%_mscmp17.not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;icmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%_msld&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%_mscmp17.not&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;!prof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!3&lt;/span&gt;
&lt;span class="nl"&gt;3:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@__msan_warning_noreturn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#6&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;unreachable&lt;/span&gt;
&lt;span class="nl"&gt;4:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;!tbaa&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!4&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;%call6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@fread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;%cmp7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;icmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%call6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%cmp7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%while.body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%while.end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="section" id="compiler-optimization"&gt;
&lt;h3&gt;Compiler Optimization&lt;/h3&gt;
&lt;p&gt;The astute reader would have noticed that in the original C code, there were two
stack variables: &lt;tt class="docutils literal"&gt;buffer&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;n&lt;/tt&gt;. Looking at the output of clang without
optimization, we can see both being allocated &lt;strong&gt;and&lt;/strong&gt; initialized in the
function prologue&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;span class="nv nv-Anonymous"&gt;%3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;
&lt;span class="k"&gt;store&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.memset.p0.i64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;-86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;!annotation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!4&lt;/span&gt;
&lt;span class="k"&gt;store&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;-6148914691236517206&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;!annotation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!4&lt;/span&gt;
&lt;span class="k"&gt;br&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;store&lt;/tt&gt; is being optimized out by the compiler (thanks to a following
&lt;tt class="docutils literal"&gt;write&lt;/tt&gt;) to save the result of &lt;tt class="docutils literal"&gt;fread&lt;/tt&gt;. That's great news! It means that the
front-end compiler (here Clang) can generate initialisation for every stack
variable, and let the optimizer (here LLVM) get rid of the redundant initialisation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="lowering"&gt;
&lt;h3&gt;Lowering&lt;/h3&gt;
&lt;p&gt;When generating assembly code from the LLVM IR, the compiler faces a lot of
choices, one of which being «should I turn a call to &lt;tt class="docutils literal"&gt;llvm.memset&lt;/tt&gt; into a
block of instructions, or into a call to libc's &lt;tt class="docutils literal"&gt;memset&lt;/tt&gt;?». For large buffer
it chooses the latter, but were the buffer smaller, a bunch of &lt;tt class="docutils literal"&gt;mov&lt;/tt&gt; (or
&lt;tt class="docutils literal"&gt;movaps&lt;/tt&gt;, you get the idea) would be generated instead.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="evaluating-using-ftrivial-auto-var-init-xxxx-on-firefox"&gt;
&lt;h2&gt;Evaluating Using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init=xxxx&lt;/span&gt;&lt;/tt&gt; on Firefox&lt;/h2&gt;
&lt;p&gt;As a security-hardening flag, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init=xxxx&lt;/span&gt;&lt;/tt&gt; has been
considered as a default flag to build Firefox. But as noted above, it (may) have
an impact on runtime performance. In here, we will focus on the impact on
shippable Firefox Linux when running the &lt;a class="reference external" href="https://github.com/WebKit/Speedometer"&gt;Speedometer3 benchmark&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Following table summarizes the result we get with the three setups, on three
different desktop targets (actual details are available
&lt;a class="reference external" href="https://treeherder.mozilla.org/perfherder/compare?originalProject=try&amp;amp;originalRevision=72364426229394f8b7818f4e690af89c7004989e&amp;amp;newProject=try&amp;amp;newRevision=7c8edf2bf86ee0df8fa7107dd937d5de5f0f823b&amp;amp;page=1&amp;amp;framework=13"&gt;for the pattern setting&lt;/a&gt;
and
&lt;a class="reference external" href="https://treeherder.mozilla.org/perfherder/compare?originalProject=try&amp;amp;originalRevision=72364426229394f8b7818f4e690af89c7004989e&amp;amp;newProject=try&amp;amp;newRevision=73a082680aeccbe3f7d5bf7a12c62f522e794254&amp;amp;page=1&amp;amp;framework=13"&gt;for the zero setting&lt;/a&gt;.&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;caption&gt;Speedometer3 results dependeing on &lt;cite&gt;-ftrivial-auto-var-init&lt;/cite&gt;   setting&lt;/caption&gt;
&lt;colgroup&gt;
&lt;col width="25%" /&gt;
&lt;col width="25%" /&gt;
&lt;col width="25%" /&gt;
&lt;col width="25%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;platform&lt;/th&gt;
&lt;th class="head"&gt;default&lt;/th&gt;
&lt;th class="head"&gt;pattern&lt;/th&gt;
&lt;th class="head"&gt;zero&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;linux64&lt;/td&gt;
&lt;td&gt;8.97&lt;/td&gt;
&lt;td&gt;8.82&lt;/td&gt;
&lt;td&gt;8.87&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;osx10-64&lt;/td&gt;
&lt;td&gt;12.05&lt;/td&gt;
&lt;td&gt;11.95&lt;/td&gt;
&lt;td&gt;12.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;win10-64&lt;/td&gt;
&lt;td&gt;12.64&lt;/td&gt;
&lt;td&gt;12.46&lt;/td&gt;
&lt;td&gt;12.47&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A 1% regression on performance is not a trade off we are ready to make anytime
soon. Can we do better?&lt;/p&gt;
&lt;div class="section" id="spotting-the-culprit"&gt;
&lt;h3&gt;Spotting the culprit&lt;/h3&gt;
&lt;p&gt;LLVM has a reporting mechanism that helps tracking down the behavior of the
optimizer. In particular, it can report any instruction that ends up with an
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;!{!&amp;quot;auto-init&amp;quot;}&lt;/span&gt;&lt;/tt&gt; annotation at the end of the optimization pipeline, using
the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Rpass-missed=annotation-remarks&lt;/span&gt;&lt;/tt&gt; flag. On our toy example from the first
section, we get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;cat.c&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;-o-&lt;span class="w"&gt; &lt;/span&gt;-ftrivial-auto-var-init&lt;span class="o"&gt;=&lt;/span&gt;zero&lt;span class="w"&gt; &lt;/span&gt;-Rpass-missed&lt;span class="o"&gt;=&lt;/span&gt;annotation-remarks
cat.c:4:8:&lt;span class="w"&gt; &lt;/span&gt;remark:&lt;span class="w"&gt; &lt;/span&gt;Call&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;memset&lt;span class="w"&gt; &lt;/span&gt;inserted&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;-ftrivial-auto-var-init.&lt;span class="w"&gt; &lt;/span&gt;Memory&lt;span class="w"&gt; &lt;/span&gt;operation&lt;span class="w"&gt; &lt;/span&gt;size:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes.
&lt;span class="w"&gt; &lt;/span&gt;Written&lt;span class="w"&gt; &lt;/span&gt;Variables:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;unknown&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-Rpass-missed&lt;span class="o"&gt;=&lt;/span&gt;annotation-remarks&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's pretty nice to spot inserted instructions that end up not being
optimized, but as one can expect from a codebase as large as Firefox's, it
generates too much information.&lt;/p&gt;
&lt;p&gt;Fortunately we can combine this with profile information, through
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fdiagnostics-hotness-threshold=auto&lt;/span&gt;&lt;/tt&gt;, to sort out the most impactful
insertion, and analyze the result.&lt;/p&gt;
&lt;p&gt;So the methodology becomes:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Compile Firefox with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init=zero&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fprofile-generate&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;Train Firefox on Speedometer3 to gather profile information.&lt;/li&gt;
&lt;li&gt;Recompile Firefox with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init=zero&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fprofile-use&lt;/span&gt;&lt;/tt&gt;,
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Rpass-missed=annotation-remarks&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fdiagnostics-hotness-threshold=auto&lt;/span&gt;&lt;/tt&gt;, logging the result.&lt;/li&gt;
&lt;li&gt;Do something smart (?) with the result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Applied to our toy program, this summarizes into:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;cat.c&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;cat.generate&lt;span class="w"&gt; &lt;/span&gt;-ftrivial-auto-var-init&lt;span class="o"&gt;=&lt;/span&gt;zero&lt;span class="w"&gt; &lt;/span&gt;-fprofile-generate
$&lt;span class="w"&gt; &lt;/span&gt;./cat.generate&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;cat.c
$&lt;span class="w"&gt; &lt;/span&gt;llvm-profdata&lt;span class="w"&gt; &lt;/span&gt;merge&lt;span class="w"&gt; &lt;/span&gt;*.profraw&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;merged.profdata
$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;cat.c&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;cat.generate&lt;span class="w"&gt; &lt;/span&gt;-ftrivial-auto-var-init&lt;span class="o"&gt;=&lt;/span&gt;zero&lt;span class="w"&gt; &lt;/span&gt;-fprofile-use&lt;span class="o"&gt;=&lt;/span&gt;merged.profdata&lt;span class="w"&gt; &lt;/span&gt;-Rpass-missed&lt;span class="o"&gt;=&lt;/span&gt;annotation-remarks&lt;span class="w"&gt; &lt;/span&gt;-fdiagnostics-hotness-threshold&lt;span class="o"&gt;=&lt;/span&gt;auto
cat.c:4:8:&lt;span class="w"&gt; &lt;/span&gt;remark:&lt;span class="w"&gt; &lt;/span&gt;Call&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;memset&lt;span class="w"&gt; &lt;/span&gt;inserted&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;-ftrivial-auto-var-init.&lt;span class="w"&gt; &lt;/span&gt;Memory&lt;span class="w"&gt; &lt;/span&gt;operation&lt;span class="w"&gt; &lt;/span&gt;size:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes.
&lt;span class="w"&gt; &lt;/span&gt;Written&lt;span class="w"&gt; &lt;/span&gt;Variables:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;unknown&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;hotness:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-Rpass-missed&lt;span class="o"&gt;=&lt;/span&gt;annotation-remarks&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;char&lt;span class="w"&gt; &lt;/span&gt;buffer&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;^
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When applying the above to Firefox, we spotted a few recurring situation I'm
going to cover in the following section.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="recurring-nightmare"&gt;
&lt;h2&gt;Recurring Nightmare&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Bonus point if you get the reference to the MTG emblematic card.&lt;/em&gt;&lt;/p&gt;
&lt;div class="section" id="smallvector-and-friends"&gt;
&lt;h3&gt;SmallVector and Friends&lt;/h3&gt;
&lt;p&gt;It is a common optimization to provide data types that preallocates some memory,
aiming at stack allocation, and switching to heap allocation depending on the
usage. In the LLVM codebase those are &lt;tt class="docutils literal"&gt;SmallVector&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;SmallString&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;SmallPtrSet&lt;/tt&gt; etc. Similar performance-oriented data structures can be found in the Firefox codebase in the form of &lt;tt class="docutils literal"&gt;nsAutoCString&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;AutoTArray&lt;/tt&gt;. These data types provide an interesting challenge &lt;em&gt;wrt.&lt;/em&gt; trivial auto var init: they typically are performance oriented data structure whose buffer is &lt;em&gt;not&lt;/em&gt; going to be used right away. It is very unlikely that the compiler can optimize out the initialization of this buffer! Consider the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// copy a C string into a nsAutoCStringN&lt;/span&gt;
&lt;span class="n"&gt;nsAutoCStringN&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Depending on the &lt;em&gt;runtime&lt;/em&gt; size of &lt;tt class="docutils literal"&gt;buffer&lt;/tt&gt;, the pre-allocated buffer of
&lt;tt class="docutils literal"&gt;line&lt;/tt&gt; is going to be either partially filled, totally filled or unused in
favor of stack allocation. Only in the second case is it valid to get rid of the
full initialization... And there is no way the compiler could handle that
statically.&lt;/p&gt;
&lt;p&gt;In some cases it is possible to avoid using these data structures (see &lt;a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1850948"&gt;Bug
1850948&lt;/a&gt;)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="initialization-within-a-loop"&gt;
&lt;h3&gt;Initialization within a Loop&lt;/h3&gt;
&lt;p&gt;It is quite common to declare stack variables to the stricter scope needed. It
improves locality (from a code review point of view) and it avoids exposing
variable content to other code portion. However, the interaction with
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init&lt;/span&gt;&lt;/tt&gt; is not negligible. Consider the following code that
reads info from &lt;tt class="docutils literal"&gt;/proc/self/maps&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[...]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modulePath&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATH_MAX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sscanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%lx-%lx %6s %lx %*s %*x %&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH_MAX_STRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PATH_MAX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;perm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modulePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[...]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init&lt;/span&gt;&lt;/tt&gt; has the (expected!) effect of adding a &lt;tt class="docutils literal"&gt;memset&lt;/tt&gt; inside
the loop, to initialize &lt;tt class="docutils literal"&gt;modulePath&lt;/tt&gt;. The allocation itself is going to be moved
in the function prologue, but not the initialisation. This turns a
&lt;span class="formula"&gt;&lt;span class="scriptfont"&gt;O&lt;/span&gt;(1)&lt;/span&gt; instruction into a &lt;span class="formula"&gt;&lt;span class="scriptfont"&gt;O&lt;/span&gt;(&lt;i&gt;n&lt;/i&gt;×&lt;i&gt;m&lt;/i&gt;)&lt;/span&gt; one, where &lt;span class="formula"&gt;&lt;i&gt;n&lt;/i&gt;&lt;/span&gt; is
the size of the buffer and &lt;span class="formula"&gt;&lt;i&gt;m&lt;/i&gt;&lt;/span&gt; is the number of loop iteration. Not ideal.&lt;/p&gt;
&lt;p&gt;The trivial (but manual) fix here is to rewrite the code as follow:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modulePath&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PATH_MAX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[...]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;modulePath&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sscanf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%lx-%lx %6s %lx %*s %*x %&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH_MAX_STRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PATH_MAX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;perm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modulePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[...]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is not strictly equivalent though: if the loop is never entered, we still
pay for one initialisation, and the &lt;span class="formula"&gt;&lt;i&gt;k&lt;/i&gt;&lt;sup&gt;&lt;span class="text"&gt;th&lt;/span&gt;&lt;/sup&gt;&lt;/span&gt; iteration can &lt;em&gt;see&lt;/em&gt; the
content of previous iteration's buffer. We applied a similar patch for &lt;a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1850951"&gt;Bug
1850951&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="empty-class"&gt;
&lt;h3&gt;Empty Class&lt;/h3&gt;
&lt;p&gt;Every object that may have its address taken must have a size of at least one
byte. Even if it doesn't have any members. That would be the case of the
following class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Holder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Holder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;enter&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Holder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;exit&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Holder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let's imagine the compiler doesn't have access to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Holder::log()&lt;/span&gt;&lt;/tt&gt;
implementation. Or maybe it has access to it but it cannot inline it. Because it
is a member function, it takes an (implicit) reference to &lt;tt class="docutils literal"&gt;this&lt;/tt&gt; as first
parameter. So the address of the object is taken. So its size becomes one, and
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init&lt;/span&gt;&lt;/tt&gt; makes sure this padding byte is
initialized. After all, that's stack memory! Here is the LLVM bitcode output by
the compiler from the above snippet after &lt;tt class="docutils literal"&gt;clang++ &lt;span class="pre"&gt;-S&lt;/span&gt; &lt;span class="pre"&gt;-emit-llvm&lt;/span&gt; &lt;span class="pre"&gt;-O2&lt;/span&gt;
&lt;span class="pre"&gt;-ftrivial-auto-var-init=pattern&lt;/span&gt; &lt;span class="pre"&gt;-o-&lt;/span&gt; a.cpp &lt;span class="pre"&gt;-fno-exceptions&lt;/span&gt;&lt;/tt&gt; (passing
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-fno-exceptions&lt;/span&gt;&lt;/tt&gt; just to avoid the extra clutter). We can see the extra
&lt;tt class="docutils literal"&gt;store i8 &lt;span class="pre"&gt;-86,&lt;/span&gt; ptr %1, align 1, !annotation !3&lt;/tt&gt; that's not wanted, and the
&lt;tt class="docutils literal"&gt;ptr noundef nonnull align 1 dereferenceable(1) %1&lt;/tt&gt; as first parameter of
&lt;tt class="docutils literal"&gt;call void &amp;#64;_ZNK6Holder3logEv&lt;/tt&gt;, i.e. &lt;tt class="docutils literal"&gt;void &lt;span class="pre"&gt;&amp;#64;Holder::log()&lt;/span&gt; const&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dso_local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@_Z3foov&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;local_unnamed_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;alloca&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%struct.Holder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.lifetime.start.p0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#4&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;store&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;-86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;!annotation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;!3&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@.str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@_ZNK6Holder3logEv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;align&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#4&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@.str.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@llvm.lifetime.end.p0&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#4&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Can we help the compiler there? Actually we can, by informing it that &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Holder::log&lt;/span&gt;&lt;/tt&gt; doesn't need any reference to &lt;tt class="docutils literal"&gt;this&lt;/tt&gt;, while preventing it to be called without object attached:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Holder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Holder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;enter&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Holder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;exit&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log_impl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log_impl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Holder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;gets compiled into the expected:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dso_local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@_Z3foov&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;local_unnamed_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@.str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@_ZN6Holder8log_implEv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;#3&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv nv-Anonymous"&gt;%2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;tail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;noundef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;dereferenceable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;@.str.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;ret&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This approach has been used in &lt;a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1844520"&gt;Bug 1844520&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="manual-check"&gt;
&lt;h3&gt;Manual Check&lt;/h3&gt;
&lt;p&gt;At some point in the process, I decided to flag the top 100 variables reported
as initialized and hot with the attribute &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;__attribute__((uninitialized))&lt;/span&gt;&lt;/tt&gt;,
which has the effect of preventing any extra initialisation code to be inserted
by &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init&lt;/span&gt;&lt;/tt&gt;. I was very hopeful with that approach, as I
was expecting this attribute to significantly decrease the impact of auto-initialisation on performance.
Unfortunately the opposite happened:
almost no speed improvement. This tells us that the performance impact is not
due to a few hotspot but spread across the whole codebase. So the whole idea of
handling every situation one after the other is unlikely to be enough! How
depressing.&lt;/p&gt;
&lt;p&gt;Let's still have a look at a final situation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="value-semantic"&gt;
&lt;h3&gt;Value Semantic&lt;/h3&gt;
&lt;p&gt;Maybe as an inheritance of C, maybe as an inheritance of C++98, we often see
interfaces that use pass-by-reference as a way to return extra values. For
instance in the following code &lt;tt class="docutils literal"&gt;doStuff&lt;/tt&gt; returns &lt;tt class="docutils literal"&gt;false&lt;/tt&gt; in case of error,
and &lt;tt class="docutils literal"&gt;true&lt;/tt&gt; and sets &lt;tt class="docutils literal"&gt;result&lt;/tt&gt; in case of success.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;doStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From the compiler point of view, there is no guarantee that &lt;tt class="docutils literal"&gt;res&lt;/tt&gt; has been
initialized with &lt;tt class="docutils literal"&gt;doStuff&lt;/tt&gt;. And doing so would mean being able to couple value
and control-flow, something compilers are not always very good at.&lt;/p&gt;
&lt;p&gt;I've asked myself how we could &lt;em&gt;inform&lt;/em&gt; the compiler about this behavior. It
turns out LLVM does have attribute to specify interaction of parameters &lt;em&gt;wrt.&lt;/em&gt;
memory, through &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;memory(...)&lt;/span&gt;&lt;/tt&gt;. For instance, according to the &lt;a class="reference external" href="https://llvm.org/docs/LangRef.html"&gt;language
reference&lt;/a&gt; one can use &lt;tt class="docutils literal"&gt;memory(argmem:
read, inaccessiblemem: write)&lt;/tt&gt; to specify that&lt;/p&gt;
&lt;blockquote&gt;
May only read argument memory and only write inaccessible memory.&lt;/blockquote&gt;
&lt;p&gt;But there is no way to state that the function &lt;strong&gt;must&lt;/strong&gt; write to the location.
And even with that piece of information, we would have to state the write is
only done if the return value is &lt;tt class="docutils literal"&gt;true&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;One option though would be to return an &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::optional&lt;/span&gt;&lt;/tt&gt;. In that case the
problem of initializing the return value is deferred to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::optional&lt;/span&gt;&lt;/tt&gt;. In
turn &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::optional&lt;/span&gt;&lt;/tt&gt; needs to initialize its inner members, so we're only
moving the problem.&lt;/p&gt;
&lt;p&gt;This is, however, quite close to the situation we had with data structures that
preallocate memory: no normal usage of the data structure should lead to an
access of the uninitialized memory, and those data structures are critical
enough to trade security for performance. What about flagging them with a
specific attribute that would bypass the trivial initialisation mechanism? I
actually &lt;a class="reference external" href="https://reviews.llvm.org/D156337"&gt;submitted a patch&lt;/a&gt; to implement
that, only to realize that the right approach would be to allow setting the
attribute on class members, which turns out to be trickier than expected. But if
we could do this, we would impact the whole codebase by only adding a few
attributes, which is much more rewarding than mechanically tracking hotspots.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="concluding-words"&gt;
&lt;h3&gt;Concluding Words&lt;/h3&gt;
&lt;p&gt;So in the end, there was no straight-forward fix to prevent the performance
regression caused by &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init&lt;/span&gt;&lt;/tt&gt;, and Firefox is probably not
going to move there anytime soon. How disappointing?&lt;/p&gt;
&lt;p&gt;But let's be positive! In the process of trying to decrease the performance impact
of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-ftrivial-auto-var-init&lt;/span&gt;&lt;/tt&gt; on Firefox codebase, I grabbed a better understanding
of the original problem and how clang approaches it. I also came up with a methodology
to track the performance impact and iteratively improve the situation. And I
shared that knowledge with you, and there is value in it, isn't there?&lt;/p&gt;
&lt;div class="section" id="acknowledgments"&gt;
&lt;h4&gt;Acknowledgments&lt;/h4&gt;
&lt;p&gt;The author would like to thank &lt;a class="reference external" href="https://frederik-braun.com"&gt;Frederik Braun&lt;/a&gt; , Tom Ritter, Sylvestre Ledru and Tyson Smith
for the proofreading of this post and the fruitful discussion we've been having
on that topic.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="mozilla"></category></entry><entry><title>-Wglobal-constructors</title><link href="http://serge-sans-paille.github.io/pythran-stories/-wglobal-constructors.html" rel="alternate"></link><published>2023-10-02T23:00:00+02:00</published><updated>2023-10-02T23:00:00+02:00</updated><author><name>Serge Guelton</name></author><id>tag:serge-sans-paille.github.io,2023-10-02:/pythran-stories/-wglobal-constructors.html</id><summary type="html">&lt;p class="first last"&gt;What's worse than a global variable? A global variable initialized at
startup!&lt;/p&gt;
</summary><content type="html">&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;unordered_set&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unordered_set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_colors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;red&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;green&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pink&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's compile and run the snippet above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang++&lt;span class="w"&gt; &lt;/span&gt;--version
clang&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;.0.5&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Fedora&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;.0.5-2.fc36&lt;span class="o"&gt;)&lt;/span&gt;
Target:&lt;span class="w"&gt; &lt;/span&gt;x86_64-redhat-linux-gnu
Thread&lt;span class="w"&gt; &lt;/span&gt;model:&lt;span class="w"&gt; &lt;/span&gt;posix
InstalledDir:&lt;span class="w"&gt; &lt;/span&gt;/usr/bin

$&lt;span class="w"&gt; &lt;/span&gt;clang++&lt;span class="w"&gt; &lt;/span&gt;colors.cpp&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;colors&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./colors&lt;span class="w"&gt; &lt;/span&gt;green&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ok
ok
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's be a bit more pedantic and turn all warnings on:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang++&lt;span class="w"&gt; &lt;/span&gt;colors.cpp&lt;span class="w"&gt; &lt;/span&gt;-Wall&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;colors&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./colors&lt;span class="w"&gt; &lt;/span&gt;green&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ok
ok
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;No, I meant really pedantic (so that you don't waste your time trying:
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-pedantic&lt;/span&gt;&lt;/tt&gt; doesn't find anything else)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang++&lt;span class="w"&gt; &lt;/span&gt;colors.cpp&lt;span class="w"&gt; &lt;/span&gt;-Weverything&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;colors&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./colors&lt;span class="w"&gt; &lt;/span&gt;green&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ok
&lt;span class="w"&gt; &lt;/span&gt;colors.cpp:5:56:&lt;span class="w"&gt; &lt;/span&gt;warning:&lt;span class="w"&gt; &lt;/span&gt;initialization&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;initializer_list&lt;span class="w"&gt; &lt;/span&gt;object&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;incompatible&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;C++98&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-Wc++98-compat&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;const&lt;span class="w"&gt; &lt;/span&gt;std::unordered_set&amp;lt;std::string&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;primary_colors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;red&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;green&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                                                        &lt;/span&gt;^~~~~~~~~~~~~~~~~~~~~~~~
&lt;span class="w"&gt; &lt;/span&gt;colors.cpp:5:39:&lt;span class="w"&gt; &lt;/span&gt;warning:&lt;span class="w"&gt; &lt;/span&gt;declaration&lt;span class="w"&gt; &lt;/span&gt;requires&lt;span class="w"&gt; &lt;/span&gt;an&lt;span class="w"&gt; &lt;/span&gt;exit-time&lt;span class="w"&gt; &lt;/span&gt;destructor&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-Wexit-time-destructors&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;const&lt;span class="w"&gt; &lt;/span&gt;std::unordered_set&amp;lt;std::string&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;primary_colors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;red&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;green&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;^
&lt;span class="w"&gt; &lt;/span&gt;colors.cpp:5:39:&lt;span class="w"&gt; &lt;/span&gt;warning:&lt;span class="w"&gt; &lt;/span&gt;declaration&lt;span class="w"&gt; &lt;/span&gt;requires&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;global&lt;span class="w"&gt; &lt;/span&gt;destructor&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-Wglobal-constructors&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;warnings&lt;span class="w"&gt; &lt;/span&gt;generated.
&lt;span class="w"&gt; &lt;/span&gt;ok
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that's what I needed for my intro: &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Wglobal-constructors&lt;/span&gt;&lt;/tt&gt; (let's forget
about C++98, right?). &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Wexit-time-destructors&lt;/span&gt;&lt;/tt&gt; is a subset of
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Wglobal-constructors&lt;/span&gt;&lt;/tt&gt;, so let's focus on global constructors.&lt;/p&gt;
&lt;p&gt;Indeed we are creating a &lt;tt class="docutils literal"&gt;const&lt;/tt&gt; unordered set named &lt;tt class="docutils literal"&gt;colors&lt;/tt&gt;, but the
initialization code has to happen at some point. None of &lt;a class="reference external" href="https://en.cppreference.com/w/cpp/container/unordered_set/unordered_set"&gt;its constructors&lt;/a&gt; is
flagged as &lt;tt class="docutils literal"&gt;constexpr&lt;/tt&gt; so the initialization happens at startup, before the
call to the &lt;tt class="docutils literal"&gt;main&lt;/tt&gt; function.&lt;/p&gt;
&lt;p&gt;Why is it worth a warning? The &lt;a class="reference external" href="https://clang.llvm.org/docs/DiagnosticsReference.html#wglobal-constructors"&gt;clang manual&lt;/a&gt;
is not very talkative on the subject, and the &lt;a class="reference external" href="https://github.com/llvm/llvm-project/commit/47e40931c9af037ceae73ecab7db739a34160a0e"&gt;commit introducing the feature&lt;/a&gt;
is not super helpful either, but it's &lt;a class="reference external" href="https://github.com/llvm/llvm-project/pull/68084"&gt;getting better&lt;/a&gt;.
We can guess the reasons: it can cause bugs (think &lt;a class="reference external" href="StaticInitializationOrderFiasco"&gt;Static Initialization
Order Fiasco&lt;/a&gt;) and performance problems
(increased startup time).&lt;/p&gt;
&lt;div class="section" id="warming-up"&gt;
&lt;h2&gt;Warming up&lt;/h2&gt;
&lt;p&gt;The variable &lt;tt class="docutils literal"&gt;colors&lt;/tt&gt; is a set that doesn't change in size after
initialization.
&lt;em&gt;Back in the days&lt;/em&gt; I designed a small header-only C++ library called &lt;a class="reference external" href="https://github.com/serge-sans-paille/frozen/issues"&gt;frozen&lt;/a&gt; that provides &lt;em&gt;à la&lt;/em&gt;
Python frozen containers that match the standard library interface, let's use
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;cstring&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;frozen/unordered_set.h&amp;quot;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;frozen/string.h&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;string_literals&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;constexpr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unordered_set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_colors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;red&amp;quot;&lt;/span&gt;&lt;span class="n"&gt;_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;green&amp;quot;&lt;/span&gt;&lt;span class="n"&gt;_s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;blue&amp;quot;&lt;/span&gt;&lt;span class="n"&gt;_s&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pink&amp;quot;&lt;/span&gt;&lt;span class="n"&gt;_s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;primary_colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Changing a few namespaces, swapping a few headers and add some string literals and a
container size, and we're done:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang++&lt;span class="w"&gt; &lt;/span&gt;frozen_colors.cpp&lt;span class="w"&gt; &lt;/span&gt;-Wall&lt;span class="w"&gt; &lt;/span&gt;-Wglobal-constructors&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;frozen_colors&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./frozen_colors&lt;span class="w"&gt; &lt;/span&gt;green&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ok
ok
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Great! No warning, job done! Job done? Let's double check the binary and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;nm&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;frozen_colors&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;_GLOBAL__
&lt;span class="m"&gt;0000000000401070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;t&lt;span class="w"&gt; &lt;/span&gt;_GLOBAL__sub_I_frozen_colors.cpp
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's a bit suspicious, let's have a look at this symbol:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;--disassemble&lt;span class="o"&gt;=&lt;/span&gt;_GLOBAL__sub_I_frozen_colors.cpp&lt;span class="w"&gt; &lt;/span&gt;frozen_colors
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="m"&gt;0000000000401070&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;_GLOBAL__sub_I_frozen_colors.cpp&amp;gt;:
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401070&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rax
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401071&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;bf&lt;span class="w"&gt; &lt;/span&gt;3d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;x40403d,%edi
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401076&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;e8&lt;span class="w"&gt; &lt;/span&gt;d5&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt;          &lt;/span&gt;call&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;401050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;std::ios_base::Init::Init&lt;span class="o"&gt;()&lt;/span&gt;@plt&amp;gt;
&lt;span class="w"&gt;  &lt;/span&gt;40107b:&lt;span class="w"&gt;   &lt;/span&gt;bf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;x401060,%edi
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401080&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;3d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;x40403d,%esi
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401085&lt;/span&gt;:&lt;span class="w"&gt;   &lt;/span&gt;ba&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;08&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;x402008,%edx
&lt;span class="w"&gt;  &lt;/span&gt;40108a:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;58&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;pop&lt;span class="w"&gt;    &lt;/span&gt;%rax
&lt;span class="w"&gt;  &lt;/span&gt;40108b:&lt;span class="w"&gt;   &lt;/span&gt;e9&lt;span class="w"&gt; &lt;/span&gt;b0&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt; &lt;/span&gt;ff&lt;span class="w"&gt;          &lt;/span&gt;jmp&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;401040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;__cxa_atexit@plt&amp;gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ah ah, &lt;tt class="docutils literal"&gt;&amp;lt;iostream&amp;gt;&lt;/tt&gt;. The header was included out of habit in the example
(totally by accident, not hand-crafted at all), and it didn't get reported
by clang because it comes from a system header. Removing the useless header is
indeed enough to get rid of the last global constructor of our toy program (note
that we no longer have any destructor at exit either). And now that we have set
the basics, let's start…&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="digging-into-firefox-s-global-constructor"&gt;
&lt;h2&gt;Digging Into Firefox's global constructor&lt;/h2&gt;
&lt;p&gt;There's still a lot of C++ code in Firefox's codebase. Statistically, there
should be at least a dozen global constructors in it. A dozen? Hundreds!
&lt;a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1845263"&gt;This Bug&lt;/a&gt; tracks the
various attempt to remove some of them, the rest of this article is just a
collection of the various situation in which global constructors have been
successfully removed so far.&lt;/p&gt;
&lt;div class="section" id="bye-bye-iostream"&gt;
&lt;h3&gt;Bye bye, &lt;tt class="docutils literal"&gt;&amp;lt;iostream&amp;gt;&lt;/tt&gt;&lt;/h3&gt;
&lt;p&gt;Using the example above, we can adopt a very simple strategy to detect all compilation units that include &lt;tt class="docutils literal"&gt;&amp;lt;iostream&amp;gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;dist/bin/libxul.so&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;libxul.S&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# cache this call as it takes a lot of time&lt;/span&gt;
nm&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;dist/bin/libxul.so&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/_GLOBAL__/ { print $3 }&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sym&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sym&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;libxul.S&lt;span class="w"&gt; &lt;/span&gt;-A8&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;std::ios_base::Init&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sym&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then depending on the situation, we can decide what to do with the headers:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Keep it. Required if &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::cout&lt;/span&gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::cerr&lt;/span&gt;&lt;/tt&gt; (or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::clog&lt;/span&gt;&lt;/tt&gt;!) are
used&lt;/li&gt;
&lt;li&gt;Replace it by &lt;tt class="docutils literal"&gt;&amp;lt;istream&amp;gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&amp;lt;ostream&amp;gt;&lt;/tt&gt;, when only that part of the API
is needed, typically when only &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::ostream&lt;/span&gt;&lt;/tt&gt; or
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::istream&lt;/span&gt;&lt;/tt&gt; are used.&lt;/li&gt;
&lt;li&gt;Remove it. This header is often included for debugging purpose and one
forgets to remove it. Including myself ;-)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I've done so in &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D189648"&gt;Bug 1855955&lt;/a&gt;, but also in &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D188949"&gt;Bug 1854575&lt;/a&gt; which was very satisfying
because it removed the include from a google protobuf file, which was included
in 33 compilation units! The patch also got &lt;a class="reference external" href="https://github.com/protocolbuffers/protobuf/pull/14174"&gt;accepted in the upstream protobuf
repo&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="let-it-go-frozen-h"&gt;
&lt;h3&gt;Let it go, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;&amp;lt;frozen/*.h&amp;gt;&lt;/span&gt;&lt;/tt&gt;&lt;/h3&gt;
&lt;p&gt;It is very common to have small hash tables to store data mapping, and the
Firefox codebase typically have those:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;storing &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D189199"&gt;mapping between string and enums&lt;/a&gt;, a &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D189201"&gt;very common pattern&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;storing an &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D189200"&gt;allow list&lt;/a&gt;
(well, of a single element…)&lt;/li&gt;
&lt;li&gt;storing an &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D189202"&gt;array with a lot of holes as a map&lt;/a&gt; which is more memory
efficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these commits have not landed yet, but I'm very happy to revive this classic
I developed &lt;a class="reference external" href="https://blog.quarkslab.com/frozen-zero-cost-initialization-for-immutable-containers-and-various-algorithms.html"&gt;5 years ago&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="hello-constexpr"&gt;
&lt;h3&gt;Hello, &lt;tt class="docutils literal"&gt;constexpr&lt;/tt&gt;&lt;/h3&gt;
&lt;p&gt;The firefox code base &lt;a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1768116"&gt;uses C++17&lt;/a&gt;, so &lt;a class="reference external" href="https://en.cppreference.com/w/cpp/language/constinit"&gt;constinit&lt;/a&gt; is not a thing, but
&lt;cite&gt;constexpr&lt;/cite&gt; variables &lt;a class="reference external" href="https://en.cppreference.com/w/cpp/language/constexpr"&gt;must be immediately initialized&lt;/a&gt; which implies no global
constructor.&lt;/p&gt;
&lt;p&gt;Sometimes, just setting the constructor and/or the declaration as &lt;tt class="docutils literal"&gt;constexpr&lt;/tt&gt; is enough. Easy!&lt;/p&gt;
&lt;p&gt;Many time the variable is a &lt;tt class="docutils literal"&gt;static&lt;/tt&gt; &lt;tt class="docutils literal"&gt;const&lt;/tt&gt; global &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::string&lt;/span&gt;&lt;/tt&gt; in the Firefox code
base. They can be replaced by the internal &lt;tt class="docutils literal"&gt;nsLiteralCString&lt;/tt&gt; class or by an
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::string_view&lt;/span&gt;&lt;/tt&gt; depending on the code they need to interact with. In both
cases we save the runtime initialization of the string while keeping the nice
encapsulation. We've done so in &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D189140"&gt;Bug 1854969&lt;/a&gt; and &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D188888"&gt;Bug 1854490&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Special mention to &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D184550"&gt;Bug 563351&lt;/a&gt; where making a constructor
&lt;tt class="docutils literal"&gt;constexpr&lt;/tt&gt; and declaring a single variable as a &lt;em&gt;constexpr variable&lt;/em&gt; got rid of a global constructor for a static variable declared in a header, thus in all files including that header.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://phabricator.services.mozilla.com/D188842"&gt;Bug 1854410&lt;/a&gt; was somehow
similar: static variables in a header. This time the object could not be made
&lt;tt class="docutils literal"&gt;constexpr&lt;/tt&gt;, but moving the initialization to the implementation file and
having external variables decreased the overall number of duplication.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="measuring-the-impact"&gt;
&lt;h2&gt;Measuring the Impact&lt;/h2&gt;
&lt;p&gt;Theoretically, these change should impact:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Code size, as the initialization code is no longer needed;&lt;/li&gt;
&lt;li&gt;Startup time, as less code is executed at startup;&lt;/li&gt;
&lt;li&gt;Lookup time (in the case of frozen structures) because
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;frozen::unordered_(set|map)&lt;/span&gt;&lt;/tt&gt; use perfect hashing, and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;frozen::(set|map)&lt;/span&gt;&lt;/tt&gt;
use branch-less partitioning.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Point 1. may be balanced by the increase in data size (after all, the
&lt;tt class="docutils literal"&gt;constexpr&lt;/tt&gt;-initialized data structure must live somewhere). It turns out that
in the case of firefox, the resulting &lt;tt class="docutils literal"&gt;libxul.so&lt;/tt&gt; is smaller by a dozen of kB
after all the above changes.&lt;/p&gt;
&lt;p&gt;Unfortunately, Point 2. and 3. are within the measurement noise on my setup.&lt;/p&gt;
&lt;p&gt;Factually, those are not tremendous result, but let's not forget Point 4.:
Things have been learnt in the process, and shared through this write up ;-)&lt;/p&gt;
&lt;div class="section" id="acknowledgment"&gt;
&lt;h3&gt;Acknowledgment&lt;/h3&gt;
&lt;p&gt;Thanks to Sylvestre Ledru and Paul Adenot for proof-reading this post, and to all the reviewers
of the above patches!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="mozilla"></category></entry><entry><title>Shrinking a Shared Library</title><link href="http://serge-sans-paille.github.io/pythran-stories/shrinking-a-shared-library.html" rel="alternate"></link><published>2023-06-23T00:00:00+02:00</published><updated>2023-06-23T00:00:00+02:00</updated><author><name>Serge Guelton</name></author><id>tag:serge-sans-paille.github.io,2023-06-23:/pythran-stories/shrinking-a-shared-library.html</id><summary type="html">&lt;p class="first last"&gt;What is the effect of different compiler flags on the size of a shared
library? Let's explore!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Recently, I've submitted a &lt;a class="reference external" href="https://phabricator.services.mozilla.com/D179806"&gt;patch&lt;/a&gt; that shaves ~2.5MB on one
of the core Firefox library, &lt;tt class="docutils literal"&gt;libxul.so&lt;/tt&gt;. The patch is remarkably simple, but
it's a good opportunity to dive into some techniques to shrink binary size.&lt;/p&gt;
&lt;div class="section" id="generic-approach"&gt;
&lt;h2&gt;Generic Approach&lt;/h2&gt;
&lt;p&gt;We'll use the &lt;a class="reference external" href="https://github.com/madler/zlib"&gt;libz&lt;/a&gt; library
from the official &lt;a class="reference external" href="https://zlib.net/"&gt;zlib&lt;/a&gt; as an example program to build. In
this series, we use revision &lt;strong&gt;1.2.13&lt;/strong&gt;, sha1 &lt;strong&gt;04f42ceca40f73e2978b50e93806c2a18c1281fc&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The compiler used is clang &lt;strong&gt;14.0.5&lt;/strong&gt;, the linker used is lld.&lt;/p&gt;
&lt;div class="section" id="compilation-levels"&gt;
&lt;h3&gt;Compilation Levels&lt;/h3&gt;
&lt;p&gt;Let's start with the obvious approach and explore the effect of the various
optimization levels &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O0&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O1&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Oz&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O2&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O3&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;size&lt;/tt&gt; program &lt;em&gt;list section sizes and total size of binary files&lt;/em&gt;, that's
perfectly suited to our needs. We will dive into its detailed output later.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;opt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-O0&lt;span class="w"&gt; &lt;/span&gt;-O1&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-O3&lt;span class="w"&gt; &lt;/span&gt;-Oz
&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;_build
&lt;span class="w"&gt;        &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;_build
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./_build&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$opt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;/dev/null
&lt;span class="w"&gt;        &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;_build/libz.so&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;cflag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$opt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/Total/ { printf &amp;quot;%8s: %8d\n&amp;quot;, cflag, $2 }&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;table border="1" class="docutils"&gt;
&lt;caption&gt;Impact of optimization level on binary size for libz.so&lt;/caption&gt;
&lt;colgroup&gt;
&lt;col width="50%" /&gt;
&lt;col width="50%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;CFLAGS&lt;/th&gt;
&lt;th class="head"&gt;size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;-O0&lt;/td&gt;
&lt;td&gt;141608&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;-O1&lt;/td&gt;
&lt;td&gt;88164&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;-O2&lt;/td&gt;
&lt;td&gt;99532&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;-O3&lt;/td&gt;
&lt;td&gt;101644&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;-Oz&lt;/td&gt;
&lt;td&gt;81006&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Unsurprisingly &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-Oz&lt;/span&gt;&lt;/tt&gt; yields the smaller binaries. , and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O0&lt;/span&gt;&lt;/tt&gt; performs a
direct translation which uses a lot of space. Performing basic optimizations as
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O1&lt;/span&gt;&lt;/tt&gt; does generally lead to code shrinking because the optimized assembly is
more dense, and it looks like some of the optimization added by &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O2&lt;/span&gt;&lt;/tt&gt; generate
more instructions (Could be the result of &lt;em&gt;inlining&lt;/em&gt; or &lt;em&gt;loop unrolling&lt;/em&gt;).
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-O3&lt;/span&gt;&lt;/tt&gt; trades even more binary size for performance (could be the result of
&lt;em&gt;function specialization&lt;/em&gt; or more aggressive &lt;em&gt;inlining&lt;/em&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="link-time-optimization"&gt;
&lt;h3&gt;Link Time Optimization&lt;/h3&gt;
&lt;p&gt;Interestingly, using the various flavor of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-flto&lt;/span&gt;&lt;/tt&gt; also have an effect on the binary size:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-Oz&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
Total&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="m"&gt;80971&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-O2&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;102868&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;thin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-Oz&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;thin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
Total&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="m"&gt;82096&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;thin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-O2&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;thin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;102464&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Again, nothing surprising: having access to more information (through
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-flto=full&lt;/span&gt;&lt;/tt&gt;) gives more optimization space than &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-flto=thin&lt;/span&gt;&lt;/tt&gt; which
(slightly) trades performance of the generated binary for memory usage of the
actual compilation process. A trade-off we do not need to make for zlib but it's
another story for big project like Firefox.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-note-on-stripping"&gt;
&lt;h3&gt;A Note on Stripping&lt;/h3&gt;
&lt;p&gt;It's very common to compile a code with debug information:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-Oz&lt;span class="se"&gt;\ &lt;/span&gt;-g&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
.debug_loc&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="m"&gt;89689&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_abbrev&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;1716&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_info&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;33472&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_ranges&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;3744&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_str&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="m"&gt;5422&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_line&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;29136&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;244152&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The impact of debug information on code size is significant. We can compress
them using &lt;tt class="docutils literal"&gt;dwz&lt;/tt&gt; for a minor gain:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;dwz&lt;span class="w"&gt; &lt;/span&gt;libz.so&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
.debug_loc&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="m"&gt;89689&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_abbrev&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;1728&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_info&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;27563&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_ranges&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;3744&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_str&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="m"&gt;5422&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.debug_line&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;29136&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;238255&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We usually do not ship debug info as part of a binary, yet we may want to keep minimal ones:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-Oz&lt;span class="se"&gt;\ &lt;/span&gt;-gline-tables-only&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;113441&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The usual approach though is to separate debug information from the actual
binary (e.g. through &lt;tt class="docutils literal"&gt;objcopy &lt;span class="pre"&gt;--only-keep-debug&lt;/span&gt;&lt;/tt&gt;) then stripping it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;strip&lt;span class="w"&gt; &lt;/span&gt;libz.so&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;80755&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It even removes some extra bytes (by shrinking the section
&lt;tt class="docutils literal"&gt;.gnu.build.attributes&lt;/tt&gt;)!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="specializing-the-binary"&gt;
&lt;h2&gt;Specializing the Binary&lt;/h2&gt;
&lt;p&gt;For a given scenario, we may be ok with removing some of the capability of the
binary in exchange for smaller binaries.&lt;/p&gt;
&lt;div class="section" id="removing-eh-frame"&gt;
&lt;h3&gt;Removing &lt;tt class="docutils literal"&gt;.eh_frame&lt;/tt&gt;&lt;/h3&gt;
&lt;p&gt;The complete result of the best setup we have (let's forget about stripping), &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;CFLAGS=-Oz\&lt;/span&gt; &lt;span class="pre"&gt;-flto=full&lt;/span&gt;&lt;/tt&gt;, is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
libz.so&lt;span class="w"&gt;  &lt;/span&gt;:
section&lt;span class="w"&gt;                  &lt;/span&gt;size&lt;span class="w"&gt;    &lt;/span&gt;addr
.note.gnu.build-id&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;624&lt;/span&gt;
.dynsym&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;2616&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;648&lt;/span&gt;
.gnu.version&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;218&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3264&lt;/span&gt;
.gnu.version_d&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="m"&gt;420&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3484&lt;/span&gt;
.gnu.version_r&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3904&lt;/span&gt;
.gnu.hash&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;712&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3952&lt;/span&gt;
.dynstr&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;1478&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;4664&lt;/span&gt;
.rela.dyn&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;768&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;6144&lt;/span&gt;
.rela.plt&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="m"&gt;1056&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;6912&lt;/span&gt;
.rodata&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;17832&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;7968&lt;/span&gt;
.eh_frame_hdr&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="m"&gt;1076&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;25800&lt;/span&gt;
.eh_frame&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="m"&gt;7764&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;26880&lt;/span&gt;
.text&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;44592&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;38752&lt;/span&gt;
.init&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;27&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;83344&lt;/span&gt;
.fini&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;83372&lt;/span&gt;
.plt&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;720&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;83392&lt;/span&gt;
.data.rel.ro&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;352&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;88208&lt;/span&gt;
.fini_array&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;88560&lt;/span&gt;
.init_array&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;88568&lt;/span&gt;
.dynamic&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;432&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;88576&lt;/span&gt;
.got&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;89008&lt;/span&gt;
.data&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;93136&lt;/span&gt;
.tm_clone_table&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;93136&lt;/span&gt;
.got.plt&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;376&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;93136&lt;/span&gt;
.bss&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;93512&lt;/span&gt;
.gnu.build.attributes&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;288&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.comment&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;110&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;80971&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can get rid of some bytes by removing support for stack unwinding:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="se"&gt;\ &lt;/span&gt;-Wl,--lto-O2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-Oz&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="se"&gt;\ &lt;/span&gt;-fno-unwind-tables&lt;span class="se"&gt;\ &lt;/span&gt;-fno-exceptions&lt;span class="se"&gt;\ &lt;/span&gt;-fno-asynchronous-unwind-tables&lt;span class="se"&gt;\ &lt;/span&gt;-fomit-frame-pointer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
libz.so&lt;span class="w"&gt;  &lt;/span&gt;:
section&lt;span class="w"&gt;                  &lt;/span&gt;size&lt;span class="w"&gt;    &lt;/span&gt;addr
.note.gnu.build-id&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;624&lt;/span&gt;
.dynsym&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;2616&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;648&lt;/span&gt;
.gnu.version&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;218&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3264&lt;/span&gt;
.gnu.version_d&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="m"&gt;420&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3484&lt;/span&gt;
.gnu.version_r&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3904&lt;/span&gt;
.gnu.hash&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;712&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;3952&lt;/span&gt;
.dynstr&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;1478&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;4664&lt;/span&gt;
.rela.dyn&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;768&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;6144&lt;/span&gt;
.rela.plt&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="m"&gt;1056&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;6912&lt;/span&gt;
.rodata&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;17832&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;7968&lt;/span&gt;
.eh_frame_hdr&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;25800&lt;/span&gt;
.eh_frame&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;25812&lt;/span&gt;
.text&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;44592&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;29920&lt;/span&gt;
.init&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;27&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;74512&lt;/span&gt;
.fini&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;74540&lt;/span&gt;
.plt&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;720&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;74560&lt;/span&gt;
.data.rel.ro&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;352&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;79376&lt;/span&gt;
.fini_array&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;79728&lt;/span&gt;
.init_array&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;79736&lt;/span&gt;
.dynamic&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;432&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;79744&lt;/span&gt;
.got&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;80176&lt;/span&gt;
.data&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;84304&lt;/span&gt;
.tm_clone_table&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;84304&lt;/span&gt;
.got.plt&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;376&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;84304&lt;/span&gt;
.bss&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;84680&lt;/span&gt;
.gnu.build.attributes&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;288&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.comment&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;110&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;72147&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We reduced the &lt;tt class="docutils literal"&gt;.eh_frame&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;.eh_frame_hdr&lt;/tt&gt; sections at the expense of
removing support for stack unwinding. Again, it's a trade-off but one we may want
to make. Keep in mind the frame pointer and the exception frame are very helpful
to debug a core file!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="specializing-for-a-given-usage"&gt;
&lt;h3&gt;Specializing for a given usage&lt;/h3&gt;
&lt;p&gt;Now let's compile the example code &lt;tt class="docutils literal"&gt;minigzip.c&lt;/tt&gt; (it's part of zlib source code) while linking with our shared library, and examine the used symbols:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../test/minigzip.c&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;minizip&lt;span class="w"&gt; &lt;/span&gt;-L.&lt;span class="w"&gt; &lt;/span&gt;-lz
$&lt;span class="w"&gt; &lt;/span&gt;nm&lt;span class="w"&gt; &lt;/span&gt;minizip&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; U &amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;exit@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;fclose@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;ferror@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;fileno@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;fopen@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;fprintf@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;fread@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;fwrite@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;gzclose
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;gzdopen
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;gzerror
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;gzopen
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;gzread
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;gzwrite
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;__libc_start_main@GLIBC_2.34
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;perror@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;snprintf@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;strcmp@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;strlen@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;strrchr@GLIBC_2.2.5
&lt;span class="w"&gt;                 &lt;/span&gt;U&lt;span class="w"&gt; &lt;/span&gt;unlink@GLIBC_2.2.5
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In addition to symbols from the libc, it uses a few symbols from zlib.
This doesn't cover the whole zlib ABI though. Let's shrink the library just for our
usage using a version script that only references the symbols we want to use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;../zlib.map
MYZLIB_1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;global:
&lt;span class="w"&gt;                 &lt;/span&gt;gzclose&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;gzdopen&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;gzerror&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;gzopen&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;gzread&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;gzwrite&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;local:
&lt;span class="w"&gt;      &lt;/span&gt;*&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And pass this to the linker:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LDFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-fuse-ld&lt;span class="o"&gt;=&lt;/span&gt;lld&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="se"&gt;\ &lt;/span&gt;-Wl,--gc-sections&lt;span class="se"&gt;\ &lt;/span&gt;-Wl,--version-script,../zlib.map&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;-Oz&lt;span class="se"&gt;\ &lt;/span&gt;-flto&lt;span class="o"&gt;=&lt;/span&gt;full&lt;span class="s2"&gt;&amp;quot; -fno-unwind-tables -fno-exceptions -fno-asynchronous-unwind-tables -fomit-frame-pointer -ffunction-sections -fdata-sections&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang&lt;span class="w"&gt; &lt;/span&gt;../configure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make&lt;span class="w"&gt; &lt;/span&gt;placebo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
libz.so&lt;span class="w"&gt;  &lt;/span&gt;:
section&lt;span class="w"&gt;                  &lt;/span&gt;size&lt;span class="w"&gt;    &lt;/span&gt;addr
.note.gnu.build-id&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;624&lt;/span&gt;
.dynsym&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;576&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;648&lt;/span&gt;
.gnu.version&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1224&lt;/span&gt;
.gnu.version_d&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1272&lt;/span&gt;
.gnu.version_r&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1356&lt;/span&gt;
.gnu.hash&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1408&lt;/span&gt;
.dynstr&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;281&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1468&lt;/span&gt;
.rela.dyn&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;528&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;1752&lt;/span&gt;
.rela.plt&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;336&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;2280&lt;/span&gt;
.rodata&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;15320&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;2624&lt;/span&gt;
.eh_frame_hdr&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;17944&lt;/span&gt;
.eh_frame&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;17956&lt;/span&gt;
.init&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;27&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;22056&lt;/span&gt;
.fini&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;22084&lt;/span&gt;
.text&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;32608&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;22112&lt;/span&gt;
.plt&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="m"&gt;240&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;54720&lt;/span&gt;
.data.rel.ro&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="m"&gt;272&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;59056&lt;/span&gt;
.fini_array&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;59328&lt;/span&gt;
.init_array&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;59336&lt;/span&gt;
.dynamic&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;432&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;59344&lt;/span&gt;
.got&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;59776&lt;/span&gt;
.tm_clone_table&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;63904&lt;/span&gt;
.got.plt&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;136&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;63904&lt;/span&gt;
.bss&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;64040&lt;/span&gt;
.gnu.build.attributes&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;288&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
.comment&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="m"&gt;110&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;51496&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The linker uses the visibility information to iteratively remove code
that's never referenced.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="concluding-notes"&gt;
&lt;h3&gt;Concluding Notes&lt;/h3&gt;
&lt;p&gt;Some of the remaining sections are purely informational. For instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;-j&lt;span class="w"&gt; &lt;/span&gt;.comment&lt;span class="w"&gt; &lt;/span&gt;libz.so

&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;4743433a&lt;span class="w"&gt; &lt;/span&gt;2028474e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;55292031&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;322e322e&lt;span class="w"&gt;  &lt;/span&gt;GCC:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;GNU&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;.2.
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;31203230&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32323131&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32312028&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;52656420&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20221121&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Red
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;48617420&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;31322e32&lt;span class="w"&gt; &lt;/span&gt;2e312d34&lt;span class="w"&gt; &lt;/span&gt;2900004c&lt;span class="w"&gt;  &lt;/span&gt;Hat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;.2.1-4&lt;span class="o"&gt;)&lt;/span&gt;..L
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;696e6b65&lt;span class="w"&gt; &lt;/span&gt;723a204c&lt;span class="w"&gt; &lt;/span&gt;4c442031&lt;span class="w"&gt; &lt;/span&gt;342e302e&lt;span class="w"&gt;  &lt;/span&gt;inker:&lt;span class="w"&gt; &lt;/span&gt;LLD&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;.0.
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0040&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;3500636c&lt;span class="w"&gt; &lt;/span&gt;616e6720&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;76657273&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;696f6e20&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;.clang&lt;span class="w"&gt; &lt;/span&gt;version
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0050&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;31342e30&lt;span class="w"&gt; &lt;/span&gt;2e352028&lt;span class="w"&gt; &lt;/span&gt;4665646f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;72612031&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;.0.5&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Fedora&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;342e302e&lt;span class="w"&gt; &lt;/span&gt;352d322e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;66633336&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2900&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.0.5-2.fc36&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's just some compiler version information, we can safely drop them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objcopy&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;.comment&lt;span class="w"&gt; &lt;/span&gt;libz.s
$&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;libz.so
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
Total&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="m"&gt;51386&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We could probably shave a few extra bytes, but we already came a long way ☺.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="acknowledgments"&gt;
&lt;h3&gt;Acknowledgments&lt;/h3&gt;
&lt;p&gt;Thanks to &lt;strong&gt;Sylvestre Ledru&lt;/strong&gt; and &lt;strong&gt;Lancelot Six&lt;/strong&gt; for proof-reading this post.
You rock!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="mozilla"></category></entry><entry><title>How unity builds crept into the Firefox Build System</title><link href="http://serge-sans-paille.github.io/pythran-stories/how-unity-builds-crept-into-the-firefox-build-system.html" rel="alternate"></link><published>2023-05-03T00:00:00+02:00</published><updated>2023-05-03T00:00:00+02:00</updated><author><name>Serge Guelton</name></author><id>tag:serge-sans-paille.github.io,2023-05-03:/pythran-stories/how-unity-builds-crept-into-the-firefox-build-system.html</id><summary type="html">&lt;p class="first last"&gt;Jumbo builds make C++ code compilation faster, but what happens when
you require them?&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="unity-build"&gt;
&lt;h2&gt;Unity Build&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Unity_build"&gt;Unity builds&lt;/a&gt;, a.k.a. unified build or jumbo builds, is a technique that consists in
concatenating several C or C++ files in one before invoking the compiler. This generally
leads to faster compilation time in part because it aggregates the cost of parsing the
same headers over and over.&lt;/p&gt;
&lt;p&gt;It is one of the many approach one can use to reduce C++ software compilation
time, alongside precompiled headers and C++20 modules.&lt;/p&gt;
&lt;p&gt;It is not an obscure technique: it's officially supported by CMake through
&lt;tt class="docutils literal"&gt;CMAKE_UNITY_BUILD&lt;/tt&gt; (see
&lt;a class="reference external" href="https://cmake.org/cmake/help/latest/variable/CMAKE_UNITY_BUILD.html"&gt;https://cmake.org/cmake/help/latest/variable/CMAKE_UNITY_BUILD.html&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;At some point, the Chromium project supported doing jumbo builds:
&lt;a class="reference external" href="https://chromium.googlesource.com/chromium/src.git/+/65.0.3283.0/docs/jumbo.md"&gt;https://chromium.googlesource.com/chromium/src.git/+/65.0.3283.0/docs/jumbo.md&lt;/a&gt;,
even if it got rid of it afterward
&lt;a class="reference external" href="https://groups.google.com/a/chromium.org/g/chromium-dev/c/DP9TQszzQLI"&gt;https://groups.google.com/a/chromium.org/g/chromium-dev/c/DP9TQszzQLI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is also supported by the internal build system used at Mozilla. And the
speedup is there, a unified build (the default) runs twice as fast as an hybrid
build (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--disable-unified-build&lt;/span&gt;&lt;/tt&gt;) on my setup. As a side effect, in pre-LTO
area, this also led to better performance as it makes more information available
to the compiler.&lt;/p&gt;
&lt;p&gt;Wait, did I write &lt;em&gt;hybrid build&lt;/em&gt; and not &lt;em&gt;regular build&lt;/em&gt;? As it turns out, under
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--disable-unified-build&lt;/span&gt;&lt;/tt&gt; some parts of Firefox are still built in unified
mode, because they &lt;strong&gt;require it&lt;/strong&gt;, probably for historical reason.&lt;/p&gt;
&lt;p&gt;It's great to be able to do a unified build. It's not great to have a codebase
that does not compile unless you have a unity build: static analyzers are not
used to work on non-self contained sources (see &lt;a class="reference external" href="https://github.com/clangd/clangd/issues/45"&gt;https://github.com/clangd/clangd/issues/45&lt;/a&gt;), unity build implies a slight overhead during
incremental builds. What makes it worse is that developer start to rely on
unified build and get lazy in the way they develop.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="jumbo-build-creeps"&gt;
&lt;h2&gt;Jumbo Build Creeps&lt;/h2&gt;
&lt;p&gt;In the following we assume &lt;tt class="docutils literal"&gt;a.cpp&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;b.cpp&lt;/tt&gt; are jumbo built as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// jumbo.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;a.cpp&amp;quot;&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;b.cpp&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's have fun while collecting some of the cases found in the Firefox codebase
while removing the unify build requirement.&lt;/p&gt;
&lt;div class="section" id="skipping-includes"&gt;
&lt;h3&gt;Skipping includes&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Indeed, why including a header when another compilation unit that comes &lt;em&gt;before&lt;/em&gt; you in
the unified build is including it?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="accessing-static-functions"&gt;
&lt;h3&gt;Accessing static functions&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Isn't that a good property to be able to access a function that's meant to be
private?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="trying-to-be-smart-with-macro"&gt;
&lt;h3&gt;Trying to be smart with macro&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#define FOO 1&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#ifdef FOO&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="cp"&gt;#define BAR&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Defining a macro in one compilation unit and have it affect another compilation
unit has been a real nightmare.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="static-templates"&gt;
&lt;h3&gt;Static templates&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Isn't it great when you don't need to put your template definition in the
header? Static visibility for templates &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:-)&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="template-specialization"&gt;
&lt;h3&gt;Template specialization&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// foobar.h&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef FOOBAR_H&lt;/span&gt;
&lt;span class="cp"&gt;#define FOOBAR_H&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;

&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foobar&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;int: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This one is terrible, because it doesn't give any compile time error, but a
runtime error &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:-/&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="leaking-using-namespace"&gt;
&lt;h3&gt;Leaking using namespace&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can use symbols from namespace used from other compilation unit. That's
exactly the same problem as leaking macro or static definitions: it breaks the
compilation unit scope.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="putting-function-implementation-in-header"&gt;
&lt;h3&gt;Putting function implementation in header&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// foobar.h&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef FOOBAR_H&lt;/span&gt;
&lt;span class="cp"&gt;#define FOOBAR_H&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;

&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;foobar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As each header is only included once, you can put your function definition in
your header. Easy!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="putting-constant-initializer-in-implementation"&gt;
&lt;h3&gt;Putting constant initializer in implementation&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// foobar.h&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef FOOBAR_H&lt;/span&gt;
&lt;span class="cp"&gt;#define FOOBAR_H&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;

&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VALUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;static_assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VALUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ok&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The constant expression lacks its initializer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="error-about-functions-without-a-valid-declarations-get-silented"&gt;
&lt;h3&gt;Error about functions without a valid declarations get silented&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// foobar.h&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef FOOBAR_H&lt;/span&gt;
&lt;span class="cp"&gt;#define FOOBAR_H&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;

&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Invalid forward declaration but who cares, when the definition can be found and
the compiler doesn't warn about unused forward declaration?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="unexpected-aspect-less-warnings"&gt;
&lt;h3&gt;Unexpected aspect: less warnings&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;a.cpp&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compiling &lt;tt class="docutils literal"&gt;a.cpp&lt;/tt&gt; yields an unused warning, but not compiling &lt;tt class="docutils literal"&gt;b.cpp&lt;/tt&gt;. So
hybrid builds relying on &lt;tt class="docutils literal"&gt;#including&lt;/tt&gt; multiple sources actually decrease the
warning level.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="headers-without-include-guard"&gt;
&lt;h3&gt;Headers without include guard&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// foobar.h&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="c1"&gt;// a.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;foobar.h&amp;quot;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;// b.cpp&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Foo&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Fixing the missing include for &lt;tt class="docutils literal"&gt;b.cpp&lt;/tt&gt; leads to type redefinition because the header
is not guarded.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="about-the-firefox-codebase"&gt;
&lt;h2&gt;About the Firefox codebase&lt;/h2&gt;
&lt;p&gt;The removal of &lt;tt class="docutils literal"&gt;REQUIRES_UNIFIED_BUILD&lt;/tt&gt; across the Firefox codebase was
tracked under &lt;a class="reference external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1626530"&gt;https://bugzilla.mozilla.org/show_bug.cgi?id=1626530&lt;/a&gt;. Since I
focused on this, I've landed more than 150 commits, modifying more than 800
sources files. And it's now done, no more hard requirement of unified build,
back to a normal situation.&lt;/p&gt;
&lt;p&gt;Was it worth the effort? Yes: it prevents bad coding practices, and static
analysis is now more useful compared to what it could do with unified builds.&lt;/p&gt;
&lt;p&gt;And we're sure we won't regress as our CI now builds in both unified and non-unified mode!&lt;/p&gt;
&lt;div class="section" id="acknowledgments"&gt;
&lt;h3&gt;Acknowledgments&lt;/h3&gt;
&lt;p&gt;Thanks to Paul Adenot for proof-reading this blog post and to Andi-Bogdan
Postelnicu for reviewing most of the commits mentioned above.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="mozilla"></category></entry></feed>