<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Wed Feb 07 21:58:10 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>MongoDB Jira</title>
    <link>https://jira.mongodb.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.7.1</version>
        <build-number>970001</build-number>
        <build-date>13-04-2023</build-date>
    </build-info>


<item>
            <title>[CXX-90] Crash due to static initialization order fiasco in BSON implementation</title>
                <link>https://jira.mongodb.org/browse/CXX-90</link>
                <project id="11980" key="CXX">C++ Driver</project>
                    <description>&lt;p&gt;The actual BSON implementation assumes the following static initialization order: (static) global variables of Boost Thread implementation are initialized &lt;b&gt;before&lt;/b&gt; MongoDB&apos;s global (static) variables. However, as you know it, the C/C++ standard does not guarantee this across different translation units.&lt;/p&gt;

&lt;p&gt;To give an example:&lt;br/&gt;
 1. static_fiasco.7z attachment contains two directories:&lt;br/&gt;
    a. mongodb-src-r2.0.1 - the debug variant of the static mongoclient library, against Boost 1.43. It was built with the following command:&lt;br/&gt;
      &amp;gt; scons mongoclient --d&lt;br/&gt;
    b. mongotest -  a very basic application, that uses the static mongo library from the first directory.&lt;br/&gt;
 2. running the debug variant of the mongotest.exe most of the time results in crash (just run the already built EXE file from the Debug directory).&lt;/p&gt;

&lt;p&gt;What happens? I tracked down with OllyDbg the cause of the corruption:&lt;br/&gt;
 1. Due to the fact the mongotest is linked statically with mongoclient and boost, on my computer the linker choosed to initialize mongoclient before boost.&lt;br/&gt;
 2. This is executed from the dbclient.cpp:&lt;br/&gt;
      const BSONObj getlasterrorcmdobj = fromjson(&quot;&lt;/p&gt;
{getlasterror:1}
&lt;p&gt;&quot;);&lt;br/&gt;
    It could be also other static initialization, for example from jsobjcpp:&lt;br/&gt;
      BSONObj staticNull = fromjson( &quot;&lt;/p&gt;
{&apos;&apos;:null}
&lt;p&gt;&quot; );&lt;br/&gt;
    It does not matter which one. Depends on the linker, how it constructs the array with the static initialization callbacks.&lt;br/&gt;
 3. fromjson() indirectly calls the &quot;set_current_thread_data()&quot; from boost\libs\thread\src\win32\thread.cpp&lt;br/&gt;
    Please check the 00_call_once.png screenshot with the complete callstack.&lt;br/&gt;
 4. This sets the &quot;current_thread_tls_init_flag&quot; from the thread.cpp&lt;br/&gt;
 5. When the static initialization from the mongoclient is finished the boost_thread one will be executed, which will destroy/reset the already set current_thread_tls_init_flag.&lt;br/&gt;
    Please check the 01_once_flag.png screenshot with the complete callstack.&lt;br/&gt;
 6. The next time a thread is created, like at connect, the &quot;create_current_thread_tls_key()&quot; will be called second time, because the flag was reset previously incorrectly.&lt;br/&gt;
 7. A new TLS key (index) will be allocated, causing corruption.&lt;br/&gt;
 8. It does not matter whether it is debug or release build. The release one usually crashes more subtle.&lt;/p&gt;

&lt;p&gt;Conclusion:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;fromjson() uses JsonGrammar, which uses boost spirit, which uses thread specific data. Due to the fact that fromjson() is called in static initialization phase, you cannot guarantee that the &quot;set_current_thread_data()&quot; function which uses a &quot;call_once()&quot; will be executed BEFORE the initialization of &quot;current_thread_tls_init_flag&quot;. This depends on the linker: i.e. it is random.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Possible solutions:&lt;br/&gt;
 1. Do not use fromjson() directly in the static/global variable initializations.&lt;br/&gt;
 2. Do not use boost::spirit for grammar in the static/global variable initializations.&lt;br/&gt;
 3. Do not use static linking of Mongo with Boost.&lt;/p&gt;

&lt;p&gt;I think the first two options can be dropped. It is too complicated to change the code and the logic of the C++ clases.&lt;/p&gt;

&lt;p&gt;Solution: ALWAYS use dynamic linking with Boost on Windows. This way it can be ensured that the DllMain of boost_thread, containing the initialization of the &quot;current_thread_tls_init_flag&quot;, will be called BEFORE the initialization of mongoclient specific static data. Add to SConstruct:&lt;br/&gt;
  env.Append( CPPDEFINES=[ &quot;BOOST_ALL_DYN_LINK&quot; ] )&lt;br/&gt;
and use /MD instead of /MT in release.&lt;/p&gt;

&lt;p&gt;So you should drop/deny the mongoclient.lib to be linked statically with Boost.&lt;/p&gt;</description>
                <environment>Microsoft Windows XP SP3 32 bit&lt;br/&gt;
Microsoft Visual C++ 2008&lt;br/&gt;
Boost 1.43</environment>
        <key id="24685">CXX-90</key>
            <summary>Crash due to static initialization order fiasco in BSON implementation</summary>
                <type id="1" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14703&amp;avatarType=issuetype">Bug</type>
                                            <priority id="2" iconUrl="https://jira.mongodb.org/images/icons/priorities/critical.svg">Critical - P2</priority>
                        <status id="6" iconUrl="https://jira.mongodb.org/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="success"/>
                                    <resolution id="9">Done</resolution>
                                        <assignee username="mira.carey@mongodb.com">Mira Carey</assignee>
                                    <reporter username="bszente">Balint Szente</reporter>
                        <labels>
                            <label>boost</label>
                            <label>bson</label>
                            <label>c++</label>
                            <label>client</label>
                            <label>crash</label>
                            <label>cxxmove</label>
                            <label>initialization</label>
                            <label>legacy-cxx</label>
                            <label>static</label>
                            <label>windows</label>
                    </labels>
                <created>Wed, 9 Nov 2011 16:15:40 +0000</created>
                <updated>Mon, 8 Jan 2024 15:30:44 +0000</updated>
                            <resolved>Wed, 2 Apr 2014 14:30:42 +0000</resolved>
                                                    <fixVersion>legacy-0.8.0</fixVersion>
                                                        <votes>1</votes>
                                    <watches>8</watches>
                                                                                                                <comments>
                            <comment id="543408" author="bszente" created="Thu, 10 Apr 2014 07:34:13 +0000"  >&lt;p&gt;Hello Jason!&lt;/p&gt;

&lt;p&gt;Thank you for the update on this issue. I&apos;m glad to hear this bug was been fixed.&lt;br/&gt;
Of course, it is difficult to reproduce such fiasco errors, because they depend on the linker how it generates the final executable file, process that you cannot control. So it depends also on &quot;(bad) luck&quot; if you encounter it.&lt;/p&gt;

&lt;p&gt;Not relying on boost::spirit definitely solves this problem. So it is OK from my part, I consider this bug fixed.&lt;/p&gt;

&lt;p&gt;On the other hand, it is good to avoid static initialization of complex objects in C++ when multiple translation units are involved, as Andy wrote in the second comment.&lt;/p&gt;

&lt;p&gt;Thank you,&lt;br/&gt;
Balint&lt;/p&gt;</comment>
                            <comment id="532601" author="jason.carey" created="Wed, 2 Apr 2014 14:30:42 +0000"  >&lt;p&gt;Given that the fiasco problem seems resolved to the best of my understanding, I&apos;m closing this out now.&lt;/p&gt;

&lt;p&gt;If you have trouble in the future, please feel free to open a new ticket.&lt;/p&gt;</comment>
                            <comment id="518416" author="jason.carey" created="Tue, 18 Mar 2014 15:50:42 +0000"  >&lt;p&gt;The C++ driver no longer relies on boost::spirit for JSON parsing, so this particular initialization order fiasco should no longer be possible.  Additionally, I&apos;ve had a chance to run clang&apos;s address sanitizer with checks for additional fiasco&apos;s and haven&apos;t found any that aren&apos;t appropriately guarded.&lt;/p&gt;

&lt;p&gt;If you&apos;d like to retest, or have additional concerns, I&apos;m happy to continue the conversation.  If not, I&apos;ll close this out in a couple of days as fixed.&lt;/p&gt;</comment>
                            <comment id="74666" author="bszente" created="Tue, 20 Dec 2011 09:17:41 +0000"  >&lt;p&gt;Indeed, this would be the best (and maybe the only) long term solution. Unfortunately, the static initializations in C++ are &lt;em&gt;safe&lt;/em&gt;, if and only if they use functions/data from the same translation unit where they reside. Otherwise, you never know when you will encounter such a situation again. &lt;/p&gt;</comment>
                            <comment id="74460" author="schwerin" created="Mon, 19 Dec 2011 17:57:22 +0000"  >&lt;p&gt;I actually think that option 1, not using fromjson in static initializers, is achievable.  We should be out of the business of complex static initializers to begin with.  A plausible solution, which I have used elsewhere, is to move startup-time initialization of complex objects into functions.  Those functions are marked using some macro magic with their dependencies, and then a InitMongo() function gets placed at the top of main(), which walks the graph and runs the init functions in a topsort order.&lt;/p&gt;

&lt;p&gt;With a modicum of cleverness, systems like this aren&apos;t painful to work with.  The only loss is that startup-initialized objects can no longer be declared as &quot;const&quot;.&lt;/p&gt;

&lt;p&gt;This more general solution will hopefully also save us some future pain.&lt;/p&gt;</comment>
                            <comment id="65855" author="bszente" created="Thu, 10 Nov 2011 09:23:42 +0000"  >&lt;p&gt;How can I edit the description of this ticket to apply wiki formatting for better readability?&lt;/p&gt;</comment>
                    </comments>
                <issuelinks>
                            <issuelinktype id="10011">
                    <name>Depends</name>
                                            <outwardlinks description="depends on">
                                        <issuelink>
            <issuekey id="31669">SERVER-5112</issuekey>
        </issuelink>
                            </outwardlinks>
                                                        </issuelinktype>
                            <issuelinktype id="10012">
                    <name>Related</name>
                                            <outwardlinks description="related to">
                                                        </outwardlinks>
                                                        </issuelinktype>
                    </issuelinks>
                <attachments>
                            <attachment id="13777" name="00_call_once.png" size="154349" author="bszente" created="Wed, 9 Nov 2011 16:15:40 +0000"/>
                            <attachment id="13778" name="01_once_flag.png" size="124028" author="bszente" created="Wed, 9 Nov 2011 16:15:40 +0000"/>
                            <attachment id="13776" name="static_fiasco.7z" size="21649881" author="bszente" created="Wed, 9 Nov 2011 16:15:40 +0000"/>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|hrgjtb:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10558" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>10163</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                        <customfield id="customfield_22279" key="com.atlassian.jira.plugin.system.customfieldtypes:labels">
                        <customfieldname>Server Compat</customfieldname>
                        <customfieldvalues>
                                        <label>2.3</label>
    
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        </customfields>
    </item>
</channel>
</rss>