Skip to content

Pitch.TryParse("C1073741823") succeeds as C-1: octave arithmetic wraps, and "C 4 " is accepted too #307

Description

@matt-edmondson

What's wrong

Pitch computes the MIDI number as ((octave + 1) * 12) + letter + accidental in unchecked int, so a huge octave wraps around into the 0..127 range and passes the range check.

Where

  • Semantics.Music/Pitch.cs:81-86 (TryParse):
    if (!int.TryParse(name[index..], NumberStyles.Integer, CultureInfo.InvariantCulture, out int octave)) return false;
    int midi = ((octave + 1) * 12) + (int)letter + accidental;
    if (midi is < 0 or > 127) return false;
  • Semantics.Music/Pitch.cs:46 (Create(NoteLetter, Accidental, int octave)) uses the same expression.

Failure scenarios

These were reproduced against the built library on .NET 10:

  • (1073741823 + 1) * 12 wraps to 0, so:
    • Pitch.TryParse("C1073741823", out var p) returns true with p = C-1 (MIDI 0).
    • Pitch.Create(NoteLetter.C, Accidental.Natural, 1073741823) returns C-1 instead of throwing the documented ArgumentOutOfRangeException.
  • NumberStyles.Integer allows leading and trailing whitespace and a leading sign, so "C 4 " and "C+4" parse. They then print back as "C4", which breaks the round-trip/canonical-text contract that the type-safe-factories work set up for Music types.

Suggested fix

  • Range-check the octave before the multiplication. Any octave outside roughly −2..10 cannot produce MIDI 0..127 even with accidentals, so reject it early. Alternatively, compute in long.
  • Parse the octave with NumberStyles.AllowLeadingSign only.
  • Add tests for "C1073741823", "C 4", "C+4", and the typed factory with int.MaxValue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions