Boost C++ Libraries: Ticket #8414: flyweights causes weird library initialization error https://svn.boost.org/trac10/ticket/8414 <p> the bug is reproduced with the following test case: </p> <p> g++ main.cpp -o xmain -ldl </p> <p> main.cpp: #include &lt;dlfcn.h&gt; #include &lt;iostream&gt; int main() { </p> <blockquote> <p> std::cout &lt;&lt; "load: " &lt;&lt; std::endl; void *foo = dlopen("./libpluginTest.so", RTLD_NOW); std::cout &lt;&lt; "load: library loaded "&lt;&lt; foo &lt;&lt; std::endl; if (dlclose(foo) &lt; 0) { </p> <blockquote> <p> std::cout &lt;&lt; "load: library close failed " &lt;&lt; std::endl; return 1; </p> </blockquote> <p> } std::cout &lt;&lt; "load: library closed " &lt;&lt; std::endl; return 0; </p> </blockquote> <p> } </p> <p> --- g++ -I/path/to/boost/includes -fPIC -shared -rdynamic test_plugin.cpp -o libpluginTest.so -L/path/to/boost/libs -lrt </p> <p> test_plugin.cpp: #include &lt;iostream&gt; <em>#include &lt;boost/flyweight/intermodule_holder.hpp&gt; #include &lt;boost/flyweight.hpp&gt; </em></p> <p> typedef boost::flyweight&lt; std::string &gt; SymbolName_t; </p> <p> SymbolName_t getEmptyStringSymbol() { </p> <blockquote> <p> SymbolName_t empty(""); return empty; </p> </blockquote> <blockquote> <p> } </p> </blockquote> <p> void <span class="underline">attribute</span> ((constructor)) library_init() { </p> <blockquote> <p> std::cout &lt;&lt; "Library constructor: " &lt;&lt; std::endl; </p> </blockquote> <p> } void <span class="underline">attribute</span> ((destructor)) library_fini() { </p> <blockquote> <p> std::cout &lt;&lt; "Library destructor:" &lt;&lt; std::endl; </p> </blockquote> <p> } </p> <p> this program outputs the following: </p> <p> load: Library constructor: address of static cbContainer is: load: library loaded 0x1226030 load: library closed Library destructor: </p> <p> as this shows, the library destructor is called at program termination, and NOT before dlclose returns, which is the expected behavior. If we comment the function 'getEmptyStringSymbol', the resulting output is: </p> <p> load: Library constructor: address of static cbContainer is: load: library loaded 0x1b0b030 Library destructor: load: library closed </p> <p> which is the expected behavior </p> <p> this bug has been reproduced on the following compilers: </p> <p> g++-4.6 (<a class="missing wiki">Ubuntu/Linaro</a> 4.6.3-10ubuntu1) 4.6.3 20120918 (prerelease) g++-4.7 (<a class="missing wiki">Ubuntu/Linaro</a> 4.7.2-2ubuntu1) 4.7.2 </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/8414 Trac 1.4.3 charles quarra <charlls_quarra@…> Sun, 07 Apr 2013 15:37:45 GMT attachment set https://svn.boost.org/trac10/ticket/8414 https://svn.boost.org/trac10/ticket/8414 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">test_case</span> </li> </ul> Ticket Joaquín M López Muñoz Sun, 07 Apr 2013 18:09:00 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/8414#comment:1 https://svn.boost.org/trac10/ticket/8414#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">invalid</span> </li> </ul> <p> Hi Charles, </p> <p> I've been examing the scenario and these are my conclusions (which lead me to think this is not a bug in Boost.Flyweight, hence I'm closing the ticket, please feel free to reopen if in disagreement): </p> <p> You're checking the succesfull closing of the dynamic library incorrectly: </p> <pre class="wiki"> if (dlclose(foo) &lt; 0) { ... } </pre><p> when it should be </p> <pre class="wiki"> if (dlclose(foo) != 0) { ... } </pre><p> My thesis is then that <code>dlclose</code> is then failing to close the dynamic lib because, according to the Linux documentation on the command, some other module is sharing some symbol with it. I think the shared symbol is <code>getEmptyStringSymbol</code> and the sharing module is 'libpluginTest.so' again, which, additionally to its being loaded dynamically, it's also linked at build time: </p> <p> <code>g++ -I/path/to/boost/includes -fPIC -shared -rdynamic test_plugin.cpp</code> <strong><code>-o libpluginTest.so</code></strong> <code>-L/path/to/boost/libs -lrt</code> </p> <p> My take is that if you omit <code>-o libpluginTest.so</code> everything will behave as you expect. </p> <p> Best regards, </p> Ticket charles quarra <charlls_quarra@…> Mon, 08 Apr 2013 14:14:02 GMT <link>https://svn.boost.org/trac10/ticket/8414#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8414#comment:2</guid> <description> <p> Hi joaquin, </p> <p> i don't understand what makes you believe the plugin is being link at build time; main.cpp is the executable doing the module, and it is being built with the simple command: g++ main.cpp -o xmain -ldl as you see, nothing besides the libdl for dlopen and dlclose are being linked. </p> <p> the command line 'g++ -I/path/to/boost/includes -fPIC -shared -rdynamic test_plugin.cpp -o libpluginTest.so -L/path/to/boost/libs -lrt' it is the one building and linking the plugin. Since it is a single translation unit, the linking can be done at once. The -o libxxxx.so is not required but it is a cosmetic choice to avoid having to link a library called a.out </p> <p> i hope this helps </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joaquín M López Muñoz</dc:creator> <pubDate>Mon, 08 Apr 2013 15:19:00 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/8414#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8414#comment:3</guid> <description> <p> Yep, my fault, I skimmed through the test case and thought the referred to commandline was the one used for building the main executable. </p> <p> OK, so we have <code>dlclose</code> failing for no apparent reason (can you confirm <code>dlclose</code> indeed returns something !=0?) Boost.Flyweight creates static objects for the value factory using this so-called holder: </p> <pre class="wiki">template&lt;typename C&gt; struct static_holder_class:holder_marker { static C&amp; get() { static C c; return c; } }; </pre><p> which looks suspiciously similar to the problem described at </p> <p> <a class="ext-link" href="http://stackoverflow.com/questions/11050693/dlclose-doesnt-work-with-factory-function-complex-static-in-function"><span class="icon">​</span>http://stackoverflow.com/questions/11050693/dlclose-doesnt-work-with-factory-function-complex-static-in-function</a> </p> <p> Could you try using <code>--no-gnu-unique</code> as desribed in the post above? </p> </description> <category>Ticket</category> </item> <item> <author>charles quarra <charlls_quarra@…></author> <pubDate>Mon, 08 Apr 2013 15:59:45 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/8414#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8414#comment:4</guid> <description> <p> that option is only available at build's time of the compiler, is not a run-time option. However that problem description looks pretty similar to what we are seeing here. </p> <p> So you are saying that this is a compiler bug/mis-feature? </p> </description> <category>Ticket</category> </item> <item> <author>charles quarra <charlls_quarra@…></author> <pubDate>Mon, 08 Apr 2013 16:48:16 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/8414#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8414#comment:5</guid> <description> <p> I installed the gold plugin and build the plugin with this: </p> <p> g++ -I/path/to/boost/includes -fPIC -shared -rdynamic -Wl,--no-gnu-unique test_plugin.cpp -o libpluginTest.so -L/path/to/boost/libs -lrt </p> <p> $ ld --version GNU gold (GNU Binutils for Ubuntu 2.22.90.20120924) 1.11 </p> <p> running the program produces the expected result: the library is closed before dlclose returns: </p> <p> load: Library constructor: address of static cbContainer is: load: library loaded 0x2237030 Library destructor: load: library closed </p> <p> so this is indeed a bug or misfeature of ld. I have no idea why this is the default behavior. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joaquín M López Muñoz</dc:creator> <pubDate>Mon, 08 Apr 2013 17:07:22 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/8414#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8414#comment:6</guid> <description> <p> Seems like a bug to me, rather than default behavior. Unfortunately GCC is not my area of expertise. Let's do a final try: you can resort to a user-defined holder with a slightly different behavior wrt static construction: </p> <pre class="wiki">template&lt;typename C&gt; struct GCC_dyn_holder_class:boost::flyweights::holder_marker { static C c; static C&amp; get() { return c; } }; template&lt;typename C&gt; C GCC_dyn_holder_class&lt;C&gt;::c; struct GCC_dyn_holder:boost::flyweights::holder_marker { template&lt;typename C&gt; struct apply { typedef GCC_dyn_holder_class&lt;C&gt; type; }; }; typedef boost::flyweight&lt;std::string,GCC_dyn_holder&gt; SymbolName_t; </pre><p> Does this change anything? </p> </description> <category>Ticket</category> </item> <item> <author>charles quarra <charlls_quarra@…></author> <pubDate>Mon, 08 Apr 2013 17:45:35 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/8414#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8414#comment:7</guid> <description> <p> your sample with GCC_dyn_holder, using gold linker *WITHOUT* the --no-gnu-unique option, make dlclose behave *as expected*. But it seems to me that this kind of static holder (variable instead of function local) is not shared across modules. What do you think this implies? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joaquín M López Muñoz</dc:creator> <pubDate>Mon, 08 Apr 2013 18:05:20 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/8414#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8414#comment:8</guid> <description> <p> OK, we're getting somewhere :-) </p> <p> <em>But it seems to me that this kind of static holder (variable instead of function local) is not shared across modules.</em> </p> <p> In reality, moving <code>c</code> from function-static to global-static has nothing to do with module sharing, but it breaks some promises the lib makes as for when the flyweight factory is initialized (technically, during the so-called <em>dynamic initialization phase</em> of the program startup sequence.) Anyway, if you're not declaring any flyweight-dependent static variable in your module, then you're safe. </p> <p> Now, about module sharing. As far as I know this does not make a difference (furthermore, given the symbol sharing capabilities of GCC you probably don't need anything like <code>intermodule_holder</code>.) But you can find out by yourself: just <em>independently</em> create two <code>SymbolName_t</code>s in different modules with the same content and check whether they're equal (which happens if they both point internally to the same value, hence sharing factory.) It is important that the two objects be created independently (that is, not one copied from the other) for the test to be valid. </p> <p> Good luck, </p> </description> <category>Ticket</category> </item> </channel> </rss>