0

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?

Chris Vandevelde
  • 1,431
  • 17
  • 23
  • 3
    Tip: you can simply write `std::vector note_audio(audio.begin() + start_index, audio.begin() + end_index);` and not need to do the copy, nor all those default-constructions. – Kerrek SB Jun 27 '14 at 20:35
  • What platform, compiler, etc are you using. Is valgrind available on your system? If so, run it to get detailed information about misuse of memory. – Dale Wilson Jun 27 '14 at 21:04
  • @DaleWilson: Rookie mistake, sorry! Building C++11 on OS X Mavericks, using CMake and LLVM, I've heard Valgrind isn't working on Mavericks (http://stackoverflow.com/questions/19719762/are-there-any-alternatives-to-valgrind-on-mac-os-x-mountain-lion-and-mavericks-t) but maybe it is? (http://calvinx.com/2014/05/04/valgrind-on-mac-os-x-10-9-mavericks/). I'll see if I can get it working and report back. – Chris Vandevelde Jun 27 '14 at 23:04
  • @DaleWilson: I ran Valgrind and got a very long output, looks like there are a bunch of errors (although I'm not sure how to interpret them). The first 300-or-so lines are at this gist https://gist.github.com/cnvandev/8c47a1c42527bc7dc32f. I know `Address 0xa4a050 is 0 bytes after a block of size 25,200 alloc'd` usually refers to a write at position 25,201 on a 25,200-length vector, but I'm not sure where I'm specifying the wrong length. – Chris Vandevelde Jul 08 '14 at 01:20
  • Possibly your indices are out of bounds of the input vector? – M.M Jul 08 '14 at 02:56
  • I would suggest running this on valgrind on Linux, for more reliable output. It will most likely be very loud when things start to go wrong. – kcbanner Jul 08 '14 at 13:27
  • Also, std::copy copies [first, last) – kcbanner Jul 08 '14 at 13:28
  • The stack trace that valgrind produced for you says you are in Aquila::Mfcc::calculate(...) called from measureVector(...), accessing a vector that was allocated by Aquila in a call from measureVector() to getFft(). Check the arguments to getFft() and calculate(). – Dale Wilson Jul 08 '14 at 14:24
  • Checked indices on input vector, it's not out of bounds there. For example, on a vector of length 908800, it's crashing on [7078, 13378] (and sporadically - another run that section works but the next, [23281, 30852], doesn't). The `Aquila::SignalSource` is also the same size as the input vector...it's possible the bug is in its copy constructor. (I've also updated the constructor to use @KerrekSB's suggestion of `std::vector note_audio(audio.begin() + start_index, audio.begin() + end_index);`. I'll try Valgrind on Linux, though, maybe it'll be more helpful.) – Chris Vandevelde Jul 10 '14 at 02:02

1 Answers1

1

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.

ahjohnston25
  • 1,915
  • 15
  • 36
Chris Vandevelde
  • 1,431
  • 17
  • 23