diff --git a/src/smf_load.c b/src/smf_load.c index 7389654..84f7221 100644 --- a/src/smf_load.c +++ b/src/smf_load.c @@ -283,7 +283,7 @@ expected_sysex_length(const unsigned char status, const unsigned char *second_by { int sysex_length, len; - assert(status == 0xF0); + assert(status == 0xF0 || status == 0xF7); if (buffer_length < 3) { g_critical("SMF error: end of buffer in expected_sysex_length()."); @@ -441,7 +441,7 @@ extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_eve message_length = expected_escaped_length(status, c, buffer_length - 1, &vlq_length); - if (message_length < 0) + if (message_length <= 0) return (-3); c += vlq_length; @@ -460,12 +460,12 @@ extract_escaped_event(const unsigned char *buf, const int buffer_length, smf_eve memcpy(event->midi_buffer, c, message_length); - if (smf_event_is_valid(event)) { + if (!smf_event_is_valid(event)) { g_critical("Escaped event is invalid."); return (-1); } - if (smf_event_is_system_realtime(event) || smf_event_is_system_common(event)) { + if (!(smf_event_is_system_realtime(event) || smf_event_is_system_common(event))) { g_warning("Escaped event is not System Realtime nor System Common."); } @@ -503,11 +503,21 @@ extract_midi_event(const unsigned char *buf, const int buffer_length, smf_event_ return (-1); } - if (is_sysex_byte(status)) + if (is_sysex_byte(status)) { + if (c == buf) { + g_critical("SMF error: running status is not applicable to System Exclusive events."); + return (-2); + } return (extract_sysex_event(buf, buffer_length, event, len, last_status)); + } - if (is_escape_byte(status)) + if (is_escape_byte(status)) { + if (c == buf) { + g_critical("SMF error: running status is not applicable to Escape events."); + return (-2); + } return (extract_escaped_event(buf, buffer_length, event, len, last_status)); + } /* At this point, "c" points to first byte following the status byte. */ message_length = expected_message_length(status, c, buffer_length - (c - buf)); @@ -768,12 +778,23 @@ smf_event_is_valid(const smf_event_t *event) static int parse_mtrk_chunk(smf_track_t *track) { + smf_t *smf = track->smf; smf_event_t *event; if (parse_mtrk_header(track)) return (-1); + if (track->file_buffer + track->file_buffer_length > smf->file_buffer + smf->file_buffer_length) { + /* Truncated track? */ + track->file_buffer_length = smf->file_buffer_length - (track->file_buffer - smf->file_buffer); + } + for (;;) { + if (track->next_event_offset == track->file_buffer_length) { + g_warning("SMF warning: The track did not finish with the End of Track event."); + break; + } + event = parse_next_event(track); /* Couldn't parse an event? */ @@ -869,13 +890,17 @@ smf_load_from_memory(const void *buffer, const int buffer_length) smf->file_buffer_length = buffer_length; smf->next_chunk_offset = 0; - if (parse_mthd_chunk(smf)) + if (parse_mthd_chunk(smf)) { + smf_delete(smf); return (NULL); + } for (i = 1; i <= smf->expected_number_of_tracks; i++) { smf_track_t *track = smf_track_new(); - if (track == NULL) + if (track == NULL) { + smf_delete(smf); return (NULL); + } smf_add_track(smf, track); @@ -883,6 +908,7 @@ smf_load_from_memory(const void *buffer, const int buffer_length) if (parse_mtrk_chunk(track)) { g_warning("SMF warning: Cannot load track."); smf_track_delete(track); + break; } track->file_buffer = NULL; diff --git a/src/smf_tempo.c b/src/smf_tempo.c index a5592f1..d9a4df9 100644 --- a/src/smf_tempo.c +++ b/src/smf_tempo.c @@ -133,6 +133,11 @@ maybe_add_to_tempo_map(smf_event_t *event) /* Tempo Change? */ if (event->midi_buffer[1] == 0x51) { + if (event->midi_buffer_length < 6) { + g_critical("Tempo Change event seems truncated."); + return; + } + int new_tempo = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5]; if (new_tempo <= 0) { g_critical("Ignoring invalid tempo change.");