Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com X-Authenticated: #14308112 Date: Tue, 4 Oct 2005 18:03:22 +0300 From: Pavel Tsekov To: cygwin AT cygwin DOT com Subject: ATTN: g++ maintainer: Using string instances to pass arguments to dlls Message-ID: MIME-Version: 1.0 Content-Type: MULTIPART/MIXED; BOUNDARY="-559023410-2028948511-1128438202=:1660" X-Y-GMX-Trusted: 0 X-IsSubscribed: yes Note-from-DJ: This may be spam ---559023410-2028948511-1128438202=:1660 Content-Type: TEXT/PLAIN; charset=US-ASCII Hello, I noticed the following problem while porting an internal C++ application from linux to Cygwin. If a std::string instance created in one module (exe or dll) is passed to another say as an argument of a function call, the program crashes or hangs. I did debug for a while and it turned out that it is not the program itself that causes the crash - the cause lies in the std::string implementation, the fact that libstdc++ is provided as a static archive and that it is compiled without _GLIBCXX_FULLY_DYNAMIC_STRING defined. What happens is that each module which links agains libstdc++ get its very personal copy of the class member _S_empty_rep_storage. Now since _GLIBCXX_FULLY_DYNAMIC_STRING is not defined an empty string instance i.e. one that is created by the default constructor of std::string gets a pointer to _S_empty_rep_storage i.e. the actual allocation of memory is delayed until memory is really needed. If _GLIBCXX_FULLY_DYNAMIC_STRING is defined each string instance would get a pointer to a newly heap allocated block of memory instead . Now look at the ouput of gdb and nm used on the attached testcase: Administrator AT mordor ~/src/testcase/tc $ nm dll.dll | grep _S_empty_rep_storage 1000c030 d .data$_ZNSs4_Rep20_S_empty_rep_storageE 1000c030 D __ZNSs4_Rep20_S_empty_rep_storageE Administrator AT mordor ~/src/testcase/tc $ nm main.exe | grep _S_empty_rep_storage 00442120 d .data$_ZNSs4_Rep20_S_empty_rep_storageE 00442120 D __ZNSs4_Rep20_S_empty_rep_storageE === Breakpoint 1, main (argc=1, argv=0x10042980) at main.cc:9 9 { (gdb) n 10 string s, s1; (gdb) 12 export1 (s); (gdb) print s $1 = {static npos = 4294967295, _M_dataplus = {> = {> = {}, }, _M_p = 0x44212c ""}} (gdb) print s1 $2 = {static npos = 4294967295, _M_dataplus = {> = {> = {}, }, _M_p = 0x44212c ""}} === Here the two strings share _S_empty_rep_storage. === (gdb) step export1 (s=@0x22eea0) at dll.cc:7 7 string s1; (gdb) n 9 s1.push_back ('A'); (gdb) n 10 s.push_back ('A'); (gdb) print s $3 = (string &) @0x22eea0: {static npos = 4294967295, _M_dataplus = {> = {> = {}, }, _M_p = 0x44212c ""}} (gdb) print s1 $4 = {static npos = 4294967295, _M_dataplus = {> = {> = {}, }, _M_p = 0x10042aec "A"}} (gdb) === Here s1 points to the dll local _S_empty_rep_storage. The _M_p member of _M_dataplus is pointing to different copies of _S_empty_rep_storage - one stored in the executable which calls the dll and another one in the dll itself. Now the second push_back() call in export1 () will end up calling _M_mutate() to actually allocate storage. _M_mutate() will call _M_rep()->_M_dispose() which will end up free()-ing the memory reserved for _S_empty_rep_storage in the main exe. There is a check to prevent free()-ing _S_empty_rep_storage: #ifndef _GLIBCXX_FULLY_DYNAMIC_STRING if (__builtin_expect(this != &_S_empty_rep(), false)) #endif ... but it doesn't work well in the case when a string instance created in one module is passed to another and libstdc++ is statically linked because of the fact that each module has its own copy _S_empty_rep_storage. Can we get this fixed ? ---559023410-2028948511-1128438202=:1660 Content-Type: APPLICATION/octet-stream; name="dllstr.tar.bz2" Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename="dllstr.tar.bz2" QlpoOTFBWSZTWdKeYP4AARnfjMQQ6f//jSAFBHD+799LAIAAAIAIMAGZtLCE lSGmmjRoBo0aBoGhoGhpiAZKehqnpJpkwAmJjUwNBoAmjQSSJoTJpiZT0RhN NAAGaQGj1L1h5+ByJ55JpRkhNIkkjNnbRpHLStTnuidMKpSpCHLjubYLaNQm biPdXlcGgjJlOrVBLecMqim20ZBKW7d8BSb3tdtS0xB0egfCZVEZJQohN6tI ICcaQwVFwciKnDANjzTKObuEYYfZe4stKFIUkkkCDtYVUQpkM7kMlJ+xDPkN VTE7toUpFXhlplC6BdHaVV/s0XgM5gznFRKGVqTgE1JZSyqIIzCsR4vD5Epo oMgRjCnJisEUA+mhzVGpTzLsC71CYbYHFSszmR0oUb5cJT1UFqVBWQmtHvW6 QTDDztCRuBkrDPeoEgp1vn2Y1jLEVW87kRLJWYM4iUdDMyiGWaxOQsRefquW xQotMFoJlSEoNQw4XLkgoFzIk1xlTEgygUKVxKXELixUoppThE9y5q7DOYKr W+vEDghBB/F3JFOFCQ0p5g/g ---559023410-2028948511-1128438202=:1660 Content-Type: text/plain; charset=us-ascii -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/ ---559023410-2028948511-1128438202=:1660--