On 17/09/2009, at 2:42 AM, Jason Foreman wrote:
On Sep 16, 2009, at 5:41 AM, Aron Nopanen wrote:
On Snow Leopard (using gcc 4.2), I'm getting a 'double free' error in the guts of the C++ std::getline. The 'free' in question is being performed by std::string::reserve. This happens any time I run 'getline' (reading from cin) on a fresh, virgin string. (The error is only seen in the Debug configuration.)

Try removing these definitions from the preprocessor flags of your Debug configuration: "_GLIBCXX_DEBUG=1 _GLIBCXX_DEBUG_PEDANTIC=1" I think there are some issues when those are defined that can cause some unexpected behavior, such as what you're seeing.

Disabling _GLIBCXX_DEBUG does mask the problem. However, the issue is still present (though it probably wouldn't cause any problem in practice).

I spent some quality time with the std::string source code and figured out what's going on. It comes down to some conditional compilation driven by flag '_GLIBCXX_FULLY_DYNAMIC_STRING'. libstdc++.6.dylib was apparently compiled with it set; my program was compiled without it set.

This flag is used in basic_string.h. If not defined, all newly-created empty strings share a single, statically-defined internal representation. In the functions that deal with reference-counting shared internal string representations, there is conditionally- compiled special-casing to check for this special empty-string representation: reference counts aren't updated for it, and it's never freed.

If _GLIBCXX_FULLY_DYNAMIC_STRING is defined, this special-casing goes away. So, the empty string was created in my code (by these inlined functions) using the special static empty string representation. The call to std::getline in libstdc++.6.dylib then ended up dropping the reference to this static representation. When doing so (because _GLIBCXX_FULLY_DYNAMIC_STRING was defined), it decremented the refcount and tried to free the non-malloced object. Hence: error.

Moral of the story: C++ programs on OS X should set this compiler flag, to be consistent with the shared library settings. I'll file a radar, as I think it should be set in the various versions of c+ +config.h, but it's commented out in all of them.

For anybody who's interested, here are the relevant bits from /usr/ include/c++/4.2.1/bits/basic_string.h:

    void
    _M_dispose(const _Alloc& __a)
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
        if (__gnu_cxx::__exchange_and_add_dispatch(&this->_M_refcount,
                               -1) <= 0)
          _M_destroy(__a);
    }  // XXX MT

    void
    _M_destroy(const _Alloc&) throw();

    _CharT*
    _M_refcopy() throw()
    {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
      if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
            __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
      return _M_refdata();
    }  // XXX MT

Sorry for the digression; now back to your regular Cocoa programming.

Cheers,
Aron
_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to