Chris Vandevelde
Chris Vandevelde

Reputation: 1451

"Incorrect checksum for freed object" in library's destructors

I'm trying to do some measurements on sections of an audio signal (read as a std::vector<double>) which involves some signal-processing using Aquila. I'm calculating the MFCC constants using the same functions as in their example, but instead of an Aquila::SineGenerator I'm creating an Aquila::SignalSource from the vector, using this constructor.

My function, with irrelevant code removed, is:

void measure(std::vector<double> &output_vector, std::vector<double> &audio, int start_index, int end_index) {
    // Copy the raw note over.
    std::vector<double> note_audio(end_index - start_index);
    std::copy(audio.begin() + start_index, audio.begin() + end_index, note_audio.begin());

    // Calculate the MFCC constants.
    Aquila::SignalSource input(note_audio, 44100);
    Aquila::Mfcc mfcc(input.getSamplesCount());
    auto mfccValues = mfcc.calculate(input);

    // Copy them over to the output vector.
    for (int i = 0; i < mfccValues.size(); i++) {
        output_vector.push_back(mfccValues[i]);
    }
}

When this is run - often, but not always, the second or third time it's called - it crashes and outputs:

prog(15384,0x7fff7cafb310) malloc: *** error for object 0x7f8781863208: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

So, I fire up lldb and debug, setting a breakpoint at malloc_error_break, and get this stacktrace:

(lldb) bt
* thread #1: tid = 0x23c194, 0x00007fff8f487bc0 libsystem_malloc.dylib`malloc_error_break, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
  * frame #0: 0x00007fff8f487bc0 libsystem_malloc.dylib`malloc_error_break
    frame #1: 0x00007fff8f4815c7 libsystem_malloc.dylib`szone_error + 386
    frame #2: 0x00007fff8f482e1a libsystem_malloc.dylib`small_free_list_remove_ptr + 291
    frame #3: 0x00007fff8f47f737 libsystem_malloc.dylib`szone_free_definite_size + 3429
    frame #4: 0x00000001000029a5 prog-debug`std::__1::__vector_base<double, std::__1::allocator<double> >::~__vector_base() [inlined] std::__1::__deallocate(__ptr=0x00000001008f3800) + 421 at new:164
    frame #5: 0x000000010000299c prog-debug`std::__1::__vector_base<double, std::__1::allocator<double> >::~__vector_base() [inlined] std::__1::allocator<double>::deallocate(this=0x0000000100307888, __p=0x00000001008f3800, (null)=6300) + 8 at memory:1636
    frame #6: 0x0000000100002994 prog-debug`std::__1::__vector_base<double, std::__1::allocator<double> >::~__vector_base() [inlined] std::__1::allocator_traits<std::__1::allocator<double> >::deallocate(__a=0x0000000100307888, __p=0x00000001008f3800, __n=6300) + 24 at memory:1447
    frame #7: 0x000000010000297c prog-debug`std::__1::__vector_base<double, std::__1::allocator<double> >::~__vector_base(this=0x0000000100307878) + 380 at vector:476
    frame #8: 0x0000000100002e25 prog-debug`std::__1::vector<double, std::__1::allocator<double> >::~vector(this=0x0000000100307878) + 21 at vector:481
    frame #9: 0x0000000100002355 prog-debug`std::__1::vector<double, std::__1::allocator<double> >::~vector(this=0x0000000100307878) + 21 at vector:481
    frame #10: 0x000000010004b99c prog-debug`Aquila::MelFilter::~MelFilter() + 28
    frame #11: 0x000000010004b975 prog-debug`Aquila::MelFilter::~MelFilter() + 21
    frame #12: 0x000000010004b8b7 prog-debug`std::__1::__vector_base<Aquila::MelFilter, std::__1::allocator<Aquila::MelFilter> >::~__vector_base() + 279
    frame #13: 0x000000010004b795 prog-debug`std::__1::vector<Aquila::MelFilter, std::__1::allocator<Aquila::MelFilter> >::~vector() + 21
    frame #14: 0x000000010004b775 prog-debug`std::__1::vector<Aquila::MelFilter, std::__1::allocator<Aquila::MelFilter> >::~vector() + 21
    frame #15: 0x000000010004b755 prog-debug`Aquila::MelFilterBank::~MelFilterBank() + 21
    frame #16: 0x000000010004b545 prog-debug`Aquila::MelFilterBank::~MelFilterBank() + 21
    frame #17: 0x000000010004b463 prog-debug`Aquila::Mfcc::calculate(Aquila::SignalSource const&, unsigned long) + 323
    frame #18: 0x00000001000203b6 prog-debug`measure(the_vector=0x00007fff5fbfd8c8, audio=0x00007fff5fbfe478, start_index=7078, end_index=13378) + 1270 at measureVector.cpp:62
    frame #19: 0x0000000100018eb2 prog-debug`extractVectors(vectors=0x00007fff5fbfe4e0, audio=vector<double, std::__1::allocator<double> > at 0x00007fff5fbfe478, sample_rate=44100, bg_audio=vector<double, std::__1::allocator<double> > at 0x00007fff5fbfe460, bg_sample_rate=44100, notes=0x00007fff5fbfe490) + 3234 at extractVectors.cpp:74
    frame #20: 0x000000010002b915 prog-debug`train(results=0x00007fff5fbff620, training_path=std::__1::string at 0x00007fff5fbff608, bg_audio=vector<double, std::__1::allocator<double> > at 0x00007fff5fbff5f0, bg_sample_rate=44100, classes=0x00007fff5fbff638) + 5733 at train.cpp:44
    frame #21: 0x00000001000211d3 prog-debug`MUSE(input_path=std::__1::string at 0x00007fff5fbff948, training_path=std::__1::string at 0x00007fff5fbff930, noise_profile_path=std::__1::string at 0x00007fff5fbff908, output_path=std::__1::string at 0x00007fff5fbff8f0) + 995 at muse.cpp:44
    frame #22: 0x00000001000217fd prog-debug`main(argc=5, argv=0x00007fff5fbffab8) + 717 at muse.cpp:55

Sometimes I get that, sometimes I get other errors in the internals (you can see them here), but they all start at Aquila::Mfcc::calculate() and usually seem to involve a destructor. I've run into errors which look similar and are due to trying to return stack-based variables (oops - it's why I'm passing in my output_vector and modifying it in the function), but I don't see that here - I'm using it, then copying over the double values to my output vector. I've tried creating note_audio as a pointer with new, I've tried creating it as an array instead of std::vector both on the stack and on the heap, to no avail.

Building C++11 on OS X Mavericks, using CMake and LLVM. As per suggestion in the comments, I've saved a Gist of the first ~300 lines of a Valgrind output (although it keeps going until >100 errors). What am I missing here?

Upvotes: 0

Views: 1184

Answers (1)

Chris Vandevelde
Chris Vandevelde

Reputation: 1451

I posted this SO question to the Aquila GitHub Issues page and got back an answer from the library's creator. Credit goes to another issue for the discovery (good timing).

In short: OouraFFT, the FFT library used by Aquila, requires a vector size that is a power of 2, but doesn't complain if that's not the case, it just writes to deallocated memory on the first call to OouraFFT::fft(). The take-away lesson is to always assert conditions you need to check before going crazy on a heap.

Upvotes: 1

Related Questions