• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: C++ std::string.resize crashes in free
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: C++ std::string.resize crashes in free


  • Subject: Re: C++ std::string.resize crashes in free
  • From: Jean-Denis Muys <email@hidden>
  • Date: Sun, 20 Sep 2009 16:48:08 +0200

Thanks for the suggestion Howard, but that did not help.

After spending maybe two dozen hours trying to track this, I give up. I may come back to it later... maybe. At this point I don't have the time AND the skill set to go any deeper.

In the meantime, if anybody has Boost working within XCode, I'd be glad to hear from them.

Here is what I was able to find out.

My initial hypothesis was wrong: the linker is doing fine thank you. resize indeed calls append. I downloaded the source code for both the standard C++ library and malloc/free to go through it. As far as I can tell, the chain of event is the following:

1- Boost allocate a new object of the sample code class bus_stop_corner. It's properly constructed, and its strings are initialized to empty std::string
2- Before reading the text for the street1 std::string, Boost calls std::string:resize() to size it to the correct length (11 in the sample run).
3- resize() sees that the new size is larger than the previous size (which was 0), and so calls std::string:append() to append some memory at the end.
4- append() sees that the new length is larger than the old string capacity and calls td::string:reserve()
5- reserve() clones the old string into a newly allocated larger buffer, of the size requested, and then calls _M_dispose() on the old buffer. Here is its source code:


  template<typename _CharT, typename _Traits, typename _Alloc>
    void
    basic_string<_CharT, _Traits, _Alloc>::
    reserve(size_type __res)
    {
      if (__res != this->capacity() || _M_rep()->_M_is_shared())
        {
	  // Make sure we don't shrink below the current size
	  if (__res < this->size())
	    __res = this->size();
	  const allocator_type __a = get_allocator();
	  _CharT* __tmp = _M_rep()->_M_clone(__a, __res - this->size());
	  _M_rep()->_M_dispose(__a);
	  _M_data(__tmp);
        }
    }

6- _M_rep()->_M_dispose() calls _M_destroy()
7- _M_destroy() calls deallocate() (a method on the allocator) on the _M_rep() buffer
8- deallocate() calls the standard operator delete on its argument.


void
      deallocate(pointer __p, size_type)
      { ::operator delete(__p); }

9- delete calls the standard C routine free(), which is defined in malloc.c:

void
free(void *ptr) {
malloc_zone_t *zone;
size_t size;
if (!ptr)
return;
zone = find_registered_zone(ptr, &size);
if (!zone) {
malloc_printf("*** error for object %p: pointer being freed was not allocated\n"
"*** set a breakpoint in malloc_error_break to debug\n", ptr);
malloc_error_break();
if ((malloc_debug_flags & (SCALABLE_MALLOC_ABORT_ON_CORRUPTION| SCALABLE_MALLOC_ABORT_ON_ERROR)))
abort();
} else if (zone->version >= 6 && zone->free_definite_size)
malloc_zone_free_definite_size(zone, ptr, size);
else
malloc_zone_free(zone, ptr);
}


10- the error occurs because free() cannot find the zone from which the string buffer was allocated.

At this point I give up: I checked that the std::string whose buffer is deallocated was indeed properly constructed, ie that its buffer was allocated in a normal way:


pointer allocate(size_type __n, const void* = 0) { if (__builtin_expect(__n > this->max_size(), false)) std::__throw_bad_alloc();

	return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
      }

To go further I would need to get deep into the malloc implementation. Since the same code is running fine when built from the terminal, I suspect this would be fruitless.

I'm open to suggestions, as Boost offers quite a few nice libraries, but according to google, Boost is not very popular on the Mac.

Jean-Denis




On Sep 20, 2009, at 1:30 , Howard Hinnant wrote:

Hello Jean-Denis,

I'm not sure if this is the problem or not, but here's the first thing I would try:

In Xcode, edit "active target". Ensure that the configuration is set to Debug. Search for "preprocessor". Under "Preprocessor Macros" the following macros will be set: GCC_PREPROCESSOR_DEFINITIONS = _GLIBCXX_DEBUG=1 _GLIBCXX_DEBUG_PEDANTIC=1. Erase them. Rebuild. See if that fixes it.

-Howard

On Sep 19, 2009, at 6:41 PM, Jean-Denis Muys wrote:

Hello,

I'm facing a strange bug with some C++ sample code that only occurs when running from XCode, so I hope this is the right place to look for some help.

I just installed the Boost C++ library because I want to use its serialization facility.

Boost version 1.40 built and installed just fine following their instructions at http://www.boost.org/doc/libs/1_40_0/more/getting_started/unix-variants.html

The serialization demo program builds and runs just fine from the terminal. I built it that way:

c++ demo.cpp -o demo /usr/local/lib/libboost_serialization.dylib

Now my real project is under XCode 3.2 (on Snow Leopard) so I wanted to build and run the same demo program from XCode.

I set up a new project for a C++ tool in XCode, modified the header search path to add /usr/local/include/, added libboost_serialization.dylib, and it built without error.

However, it now breaks at runtime with the following error message from GDB:

malloc: *** error for object 0x1000581c0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug


(BTW, I did set that breakpoint, but I don't know what to do next).

The stack crawl is the following:

#0 0x7fff81291b91 in malloc_error_break
#1 0x7fff811bb083 in free
#2 0x7fff836031e8 in std::string::reserve
#3 0x7fff836032fe in std::string::append
#4 0x100156cac in boost ::archive::text_iarchive_impl<boost::archive::text_iarchive>::load at text_iarchive_impl.ipp:55
#5 0x100024a0e in boost ::archive ::load_access::load_primitive<boost::archive::text_iarchive, std::string> at iserializer.hpp:109
#6 0x100024a33 in boost ::archive ::detail::load_non_pointer_type<boost::archive::text_iarchive, std::string>::load_primitive::invoke at iserializer.hpp:332
#7 0x100024a58 in boost ::archive ::detail::load_non_pointer_type<boost::archive::text_iarchive, std::string>::invoke at iserializer.hpp:417
#8 0x100024a7d in boost::archive::load<boost::archive::text_iarchive, std::string> at iserializer.hpp:542
#9 0x100024aae in boost ::archive ::detail ::common_iarchive <boost::archive::text_iarchive>::load_override<std::string> at common_iarchive.hpp:61
#10 0x100024adb in boost ::archive ::basic_text_iarchive <boost::archive::text_iarchive>::load_override<std::string> at basic_text_iarchive.hpp:62
#11 0x100024b09 in boost ::archive ::text_iarchive_impl <boost::archive::text_iarchive>::load_override<std::string> at text_iarchive.hpp:66
#12 0x100024b3c in boost ::archive ::detail ::interface_iarchive <boost::archive::text_iarchive>::operator>><std::string> at interface_iarchive.hpp:61
#13 0x100024b73 in boost ::archive ::detail ::interface_iarchive <boost::archive::text_iarchive>::operator&<std::string> at interface_iarchive.hpp:68
#14 0x10002665e in bus_stop_corner::serialize<boost::archive::text_iarchive> at demo.cpp:123


The interesting part is frame #4, the last frame for which I have the source code:

template<class Archive>
BOOST_ARCHIVE_DECL(void)
text_iarchive_impl<Archive>::load(std::string &s)
{
  std::size_t size;
  * this->This() >> size;
  // skip separating space
  is.get();
  // borland de-allocator fixup
  #if BOOST_WORKAROUND(_RWSTD_VER, BOOST_TESTED_AT(20101))
  if(NULL != s.data())
  #endif
      s.resize(size);	// <============== crash on this line
  if(0 < size)
      is.read(&(*s.begin()), size);
}

The crash happens on the call to std::string.resize. But now what I don't get is why is the next stack frame in std::string::append and not std::string::resize?
(note that at crash time, the string s is the empty string and size == 11).


As far as I can see the problem is that the linker linked to std::string::append instead of std::string::resize.

The only explanation I have is that maybe Boost was built in a way that is incompatible with XCode.

So what does XCode do that's different from what the terminal c++ command does?

Has anyone been able to integrate Boost into an XCode project, ie those parts of Boost that are more than only headers?

Any help appreciated as I a relative newbie here.

Jean-Denis

_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


_______________________________________________ Do not post admin requests to the list. They will be ignored. Xcode-users mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
References: 
 >C++ std::string.resize calls append instead (From: Jean-Denis Muys <email@hidden>)
 >Re: C++ std::string.resize calls append instead (From: Howard Hinnant <email@hidden>)

  • Prev by Date: Re: Framework versions and linkage
  • Next by Date: SCM smart group question
  • Previous by thread: Re: C++ std::string.resize calls append instead
  • Next by thread: SCM smart group question
  • Index(es):
    • Date
    • Thread