Skip to content

Commit 8499a6c

Browse files
committed
Error instead of panic when meta file events are incorrect length
1 parent ce4641c commit 8499a6c

File tree

3 files changed

+66
-14
lines changed

3 files changed

+66
-14
lines changed

src/file.rs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -680,10 +680,17 @@ impl Meta {
680680
let end = len as usize + len_offset + 1;
681681
let data = &v[len_offset + 1..end];
682682
match meta_type {
683-
0x00 => Ok((
684-
Self::SequenceNumber(u16::from_be_bytes([data[0], data[1]])),
685-
end,
686-
)),
683+
0x00 => {
684+
if data.len() != 2 {
685+
return Err(ParseError::Invalid(
686+
"Sequence number meta event must have exactly 2 bytes",
687+
));
688+
}
689+
Ok((
690+
Self::SequenceNumber(u16::from_be_bytes([data[0], data[1]])),
691+
end,
692+
))
693+
}
687694
0x01 => Ok((Self::Text(String::from_utf8_lossy(data).to_string()), end)),
688695
0x02 => Ok((
689696
Self::Copyright(String::from_utf8_lossy(data).to_string()),
@@ -703,21 +710,54 @@ impl Meta {
703710
Self::CuePoint(String::from_utf8_lossy(data).to_string()),
704711
end,
705712
)),
706-
0x20 => Ok((Self::ChannelPrefix(Channel::from_u8(data[0])), end)),
713+
0x20 => {
714+
if data.len() != 1 {
715+
return Err(ParseError::Invalid(
716+
"ChannelPrefix meta event must have exactly 1 byte",
717+
));
718+
}
719+
Ok((Self::ChannelPrefix(Channel::from_u8(data[0])), end))
720+
}
707721
0x2F => Ok((Self::EndOfTrack, end)),
708-
0x51 => Ok((
709-
Self::SetTempo(u32::from_be_bytes([0, data[0], data[1], data[2]])),
710-
end,
711-
)),
722+
0x51 => {
723+
if data.len() != 3 {
724+
return Err(ParseError::Invalid(
725+
"SetTempo meta event must have exactly 3 bytes",
726+
));
727+
}
728+
Ok((
729+
Self::SetTempo(u32::from_be_bytes([0, data[0], data[1], data[2]])),
730+
end,
731+
))
732+
}
712733
0x54 => {
734+
if data.len() != 5 {
735+
return Err(ParseError::Invalid(
736+
"SmpteOffset meta event must have exactly 5 bytes",
737+
));
738+
}
713739
let (time, _) = HighResTimeCode::from_midi(data)?;
714740
Ok((Self::SmpteOffset(time), end))
715741
}
716-
0x58 => Ok((
717-
Self::TimeSignature(FileTimeSignature::from_midi(data)?),
718-
end,
719-
)),
720-
0x59 => Ok((Self::KeySignature(KeySignature::from_midi(data)?), end)),
742+
0x58 => {
743+
if data.len() != 4 {
744+
return Err(ParseError::Invalid(
745+
"TimeSignature meta event must have exactly 4 bytes",
746+
));
747+
}
748+
Ok((
749+
Self::TimeSignature(FileTimeSignature::from_midi(data)?),
750+
end,
751+
))
752+
}
753+
0x59 => {
754+
if data.len() != 2 {
755+
return Err(ParseError::Invalid(
756+
"KeySignature meta event must have exactly 2 bytes",
757+
));
758+
}
759+
Ok((Self::KeySignature(KeySignature::from_midi(data)?), end))
760+
}
721761
0x7F => Ok((Self::SequencerSpecific(data.to_vec()), end)),
722762
_ => Ok((
723763
Self::Unknown {

tests/file_test.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,15 @@ fn file_contains_invalid_message(file: MidiFile) -> bool {
387387
.iter()
388388
.any(|track| track.events().iter().any(|event| event.event.is_invalid()))
389389
}
390+
391+
#[test]
392+
#[cfg(feature = "file")]
393+
fn test_smf_file_zero_length_meta() {
394+
let test_file = include_bytes!("./kalinka.mid");
395+
let deserialize_result = MidiFile::from_midi(test_file);
396+
assert!(deserialize_result.is_err());
397+
assert_eq!(
398+
deserialize_result.unwrap_err().error,
399+
ParseError::Invalid("Sequence number meta event must have exactly 2 bytes")
400+
);
401+
}

tests/kalinka.mid

13 KB
Binary file not shown.

0 commit comments

Comments
 (0)