Smf::parse panics on a 14-byte file whose division high byte is 0x80 when the build enables overflow-checks. A consumer that parses untrusted .mid files aborts or unwinds instead of getting an Err.
Version: midly 0.5.3, default features.
Reproducer
fn main() {
let f: [u8; 14] = [b'M', b'T', b'h', b'd', 0, 0, 0, 6, 0, 0, 0, 0, 0x80, 0x00];
let _ = midly::Smf::parse(&f);
}
Build with overflow-checks = true. The dev profile turns it on by default.
Observed
thread 'main' panicked at src/primitive.rs:495:
attempt to negate with overflow
Expected
An Err from Smf::parse. The SMF spec says a division word with bit 15 set encodes a negative frame rate in bits 8-14. 0x80 decodes to -128, which is not one of the four legal rates (-24, -25, -29, -30), so the parser must reject it. Turning overflow-checks off produces that rejection: the same bytes return an error whose Display is invalid midi: invalid midi header.
Root cause
src/primitive.rs:495, in Timing::read:
-(bit_range!(raw, 8..16) as i8)
For a division high byte of 0x80 this evaluates -(-128i8), which overflows i8. With overflow checks off the negation wraps back to -128 and parsing returns an error, which is why the two settings behave differently.
Scope
Any input that reaches the header division field with high byte exactly 0x80. I reproduced it through Smf::parse, midly::parse, and SmfBytemap::parse. The overflow-checks setting, not the profile name, decides between the panic and the error.
Smf::parsepanics on a 14-byte file whose division high byte is0x80when the build enablesoverflow-checks. A consumer that parses untrusted.midfiles aborts or unwinds instead of getting anErr.Version: midly 0.5.3, default features.
Reproducer
Build with
overflow-checks = true. The dev profile turns it on by default.Observed
Expected
An
ErrfromSmf::parse. The SMF spec says a division word with bit 15 set encodes a negative frame rate in bits 8-14.0x80decodes to -128, which is not one of the four legal rates (-24, -25, -29, -30), so the parser must reject it. Turningoverflow-checksoff produces that rejection: the same bytes return an error whose Display isinvalid midi: invalid midi header.Root cause
src/primitive.rs:495, inTiming::read:For a division high byte of
0x80this evaluates-(-128i8), which overflowsi8. With overflow checks off the negation wraps back to -128 and parsing returns an error, which is why the two settings behave differently.Scope
Any input that reaches the header division field with high byte exactly
0x80. I reproduced it throughSmf::parse,midly::parse, andSmfBytemap::parse. Theoverflow-checkssetting, not the profile name, decides between the panic and the error.