6

I'm learning c++ by writing a program to convert MIDI files to Lilypond source files. My program is composed by two main parts:

  • a MIDI file parser, that creates an object called MidiFile.
  • a converter that takes a MidiFile objects and converts it to a Lilypond source.

Today I've started coding the converter, and while I was testing it a strange error occurred: the program dies after an exception being thrown, more specifically a HeaderError, that means that the header chunk in the MIDI file is not as expected. It wouldn't seem that strange, but this error shows up only if I add a line of code after the buggy code! I add the main() function to better explain myself

#include <iostream>
#include "midiToLyConverter.hpp"

int main(){

            // a queue to store notes that have not yet been shut down
    using MidiToLyConverter::Converter::NoteQueue;
            // representation of a note
    using MidiToLyConverter::Converter::Note;
            // the converter class
    using MidiToLyConverter::Converter::Converter;
            // the midifile class
    using Midi::MidiFile;
            // representation of a midi track
    using Midi::MidiTrack;
            // representation of a midi event
    using Midi::MidiEvents::Event;

    Parser::Parser parser = Parser::Parser(); // parser class
    parser.buildMidiFile(); // builds the midi file from a .mid
    Midi::MidiFile* midiFile = parser.getMidiFile(); // gets the MidiFile object

    // iterates over all the tracks in the MidiFile
    while(midiFile->hasNext()){
        std::cout<< "==========\n";
        MidiTrack* track = midiFile->nextTrack();
        // iterates over all events in a track
        while(track->hasNext()){
            Event* event = track->nextEvent();
            if (event->getEventType() == Midi::MidiEvents::NOTE_ON ||
                event->getEventType() == Midi::MidiEvents::NOTE_OFF
            )
                // print the event if it's a note on or off
                event->print();
        }
    }

    return 0;
}

With my main() like this, everything works properly, but, if I add something between buildMidiFile and the while loop, the function buildMidiFile throws the exception!!! Even if it's a completely unrelated instruction!

#include <iostream>
#include "midiToLyConverter.hpp"

int main(){

    using MidiToLyConverter::Converter::NoteQueue;
    using MidiToLyConverter::Converter::Note;
    using MidiToLyConverter::Converter::Converter;
    using Midi::MidiFile;
    using Midi::MidiTrack;
    using Midi::MidiEvents::Event;


    Parser::Parser parser = Parser::Parser(); // parser class
    parser.buildMidiFile(); // THE EXCEPTION IS THROWN HERE
    Midi::MidiFile* midiFile = parser.getMidiFile(); // gets the MidiFile object

            // adding this causes the exception to be thrown by the function
            // buildMidiFile() called 5 lines above!
    std::vector<bool>* vec = new std::vector<bool>();

    // iterates over all the tracks in the MidiFile
    while(midiFile->hasNext()){
        std::cout<< "==========\n";
        MidiTrack* track = midiFile->nextTrack();
        // iterates over all events in a track
        while(track->hasNext()){
            Event* event = track->nextEvent();
            if (event->getEventType() == Midi::MidiEvents::NOTE_ON ||
                event->getEventType() == Midi::MidiEvents::NOTE_OFF
            )
                // print the event if it's a note on or off
                event->print();
        }
    }

    return 0;
}

I can't explain myself how this is possible. So if anyone has ideas or advices, all the help would be greatly appreciated :) If it's helpful I can post the source code for other classes and/or functions.

7
  • 4
    Smells like a memory overwrite somewhere in the code that does get called. By declaring a new local variable you're changing the stack layout and different stuff gets overwritten now.
    – Torp
    Commented Jul 4, 2011 at 14:54
  • 3
    This could be a problem Parser::Parser parser = Parser::Parser(); as it creates a temporary Parser object and copies that to parser. Try with just Parser parser;.
    – Bo Persson
    Commented Jul 4, 2011 at 14:57
  • 4
    use some kind of memory checker (valgrind, e.g.) to see what corrupts memory/unitialized memory is being referenced
    – sehe
    Commented Jul 4, 2011 at 15:03
  • 3
    Only when you've found the real reason. You're probably corrupting the heap now, that can go undetected for a while. Commented Jul 4, 2011 at 15:20
  • 1
    Thank you for a clearly commented question :) I agree with Hans -- it's good it works, but there's almost certainly a bug in the Parser code (for instance, it writes to memory it hasn't allocated), which happened to work with the original and new code, but showed up in the intervening function. You really need to fix that somehow, as it's likely overwrite, or be overwritten by, something important sooner or later.
    – Jack V.
    Commented Jul 5, 2011 at 10:00

1 Answer 1

3

Solved! As pointed out in comments to the question, it was a problem caused by some sort of memory corruption. As suggested I used a memory checher (valgrind) and found out that it was a really stupid error: i simply forgot to initialize a variable in a for loop, something like

for (int i; i < limit ; i++)

and this led to that strange error :-) Initializing i to 0 solved the problem, and now the program works with Parser object placed either on the stack or on the heap.

So I suggest others incurring in similar problems to use a memory checker to control the memory usage of their program. Using valgrind is really simple:

valgrind --leak-check=yes yourProgram arg1 arg2

where arg1 and arg2 are the (eventual) arguments that your program requires.

Furthermore compiling your program with the -g flag (at least on g++, I don't know on other compilers), valgrind will also tell you at wich line of code the memory leak occurred.

Thanks to everybody for the help!

Regards
Matteo

1
  • What's more, with the right flags, Valgrind can also detect usage of uninitialized memory, and tell you when/where that memory was allocated. Commented Jul 5, 2011 at 18:32

Not the answer you're looking for? Browse other questions tagged or ask your own question.