Boost logo

Boost Users :

Subject: Re: [Boost-users] Serialization demo program crashes trying to free anunallocated block
From: Jean-Denis Muys (jdmuys_at_[hidden])
Date: 2009-09-20 14:40:23


Well, I spent a large number of hours since my original message, and
while I learned a lot, I could not solve my problem and I am about to
give up using Boost.

Here is what I managed to find out:

- first an foremost, the example works fine when compiled and run from
the terminal using the following command:

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

- the crash happens when running the example from the XCode IDE. Since
my real project is developed using XCode, this is a show-stopper.

- clearly, this is a Mac specific issue. I suspect something stupid,
such as a build setting or something, but I could not find what. I
posted requests for help on the XCode mailing list, but judging by the
suggestions I got, Boost is not very popular with Mac developers.

- So if somebody has managed to set up a working project under XCode
(version 3.2 preferably), I'd be really interested in that.

Now to the crash: I downloaded the source code the Mac version of the
standard C++ library and for its malloc/free routine. Using that, I
managed to reconstruct what's happening:

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, but a this point, I throw in the towel.

Jean-Denis

On Sep 20, 2009, at 21:04 , Robert Ramey wrote:

> I tried it on my system with both msvc-7.11 and gcc-4.3.2 (under
> cygwin)
> and it worked fine. I used bjam to build and test it.
>
> Robert Ramey
>
> Jean-Denis Muys wrote:
>> Hi,
>>
>> Warning: noob inside. I am new to boost, and quite a bit rusty with
>> C+
>> +, having spent the past few years with other languages.
>>
>> Nonetheless.
>>
>> I downloaded, built and installed Boost 1.40 just fine on Mac OS X
>> 10.6 (Snow Leopard).
>>
>> I set up a XCode 3.2 project to compile and run the demo.cpp program
>> delivered with the Serialization library.
>>
>> It crashes deep inside this line:
>>
>> restore_schedule(new_schedule, filename.c_str());
>>
>> GDB gives the following error message:
>>
>> malloc: *** error for object 0x1000581a0: pointer being freed was not
>> allocated
>>
>> The stack crawl shows:
>>
>> #0 0x7fff81202ff6 in __kill
>> #1 0x7fff812a4072 in abort
>> #2 0x7fff811bb095 in free
>> #3 0x7fff836031e8 in std::string::reserve
>> #4 0x7fff836032fe in std::string::append
>> #5 0x10028ccac in
>> boost


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net