An ID3v2 genre frame is split where upstream keeps it whole #44

Closed
opened 2026-08-03 20:14:19 +02:00 by Claude · 1 comment
Collaborator

Four mp3s split one TCON frame into three genres where upstream keeps it
whole: Drum And Bass;Electronic;Neurofunk is one genre upstream and three
here.

Upstream sets ATL.Settings.ID3v2_separatev2v3Values = false
(AudioFileProber.cs), which stops its reader splitting an ID3v2 v2.3 frame on
the separator those files use. The reader here splits it.

Measured after #42: 4 tracks of 4889, and 2 albums whose genre ordering
differs from upstream — a smaller and separate question about which track the
album's first genre comes from.

The remainder of the genre column agrees, so this is the last of it.

Four mp3s split one `TCON` frame into three genres where upstream keeps it whole: `Drum And Bass;Electronic;Neurofunk` is one genre upstream and three here. Upstream sets `ATL.Settings.ID3v2_separatev2v3Values = false` (`AudioFileProber.cs`), which stops its reader splitting an ID3v2 v2.3 frame on the separator those files use. The reader here splits it. Measured after #42: 4 tracks of 4889, and 2 albums whose genre *ordering* differs from upstream — a smaller and separate question about which track the album's first genre comes from. The remainder of the genre column agrees, so this is the last of it.
Author
Collaborator

This issue named the wrong cause. ID3v2_separatev2v3Values has nothing to
do with it. The setting is read in one place (ID3v2.cs:1025) and gates
/-splitting for eleven named frames — TP1, TCM, TXT, TLA, TOA, TOL, TCOM, TEXT, TOLY, TOPE, TPE1. TCON is not among them, and cannot be: the genre
branch short-circuits ahead of it at ID3v2.cs:1003, sending the frame to
extractGenreFromID3v2Code, which splits on \0, ( and ) and never on ;
or /. Turning the setting off would have changed nothing here.

The real cause is that those four files carry stacked ID3v2 tags: a 2.3 tag
at offset 0 holding TCON = "Drum And Bass;Electronic;Neurofunk", and behind it
one or two 2.4 tags holding the same three genres separated by nulls.

  • ATL reads one tag, at offset 0, and never looks past it
    (AudioDataManager.cs:531-540).
  • lofty merges consecutive ID3v2 tags, later frames replacing earlier ones
    (mpeg/read.rs), so the 2.4 frame answered and three genres came out.

Both readers were behaving correctly by their own lights; they simply disagree
about how many tags a file has.

The reader now hides the second and later front tags from lofty, so it parses
the first and then the audio. Of 4889 files in the library, exactly four have
stacked tags — the four in this issue — and a sweep of every tag item of every
file shows those four are the only ones whose values change at all.

Measured against upstream's database:

rows differing on genre
before 7 — 4 tracks, 2 album rows, 1 ordering
after 1 — the ordering

The issue said four tracks and undercounted: the two Spor album rows carried the
same split.

The review found a real defect in the fix: a second header claiming a body
larger than the file holds pushed the hidden stretch past the end, and the
subtraction that removes it underflowed — a panic in debug, a length near
u64::MAX in release. That is an mp3 whose copy was cut short mid-tag. Guarded,
with a test that reproduces the panic without it. A footer is now counted only
for 2.3 and 2.4, matching what the reader below believes.

What is left is one album, Enigma/Seven Lives Many Faces (2008), whose tracks
each agree with upstream exactly but whose album row starts from a different
track's genres. That is about the order tracks are folded into an album summary,
not about reading tags, and none of its files carry stacked tags. Filed
separately as #46.

**This issue named the wrong cause.** `ID3v2_separatev2v3Values` has nothing to do with it. The setting is read in one place (`ID3v2.cs:1025`) and gates `/`-splitting for eleven named frames — `TP1, TCM, TXT, TLA, TOA, TOL, TCOM, TEXT, TOLY, TOPE, TPE1`. `TCON` is not among them, and cannot be: the genre branch short-circuits ahead of it at `ID3v2.cs:1003`, sending the frame to `extractGenreFromID3v2Code`, which splits on `\0`, `(` and `)` and never on `;` or `/`. Turning the setting off would have changed nothing here. The real cause is that those four files carry **stacked ID3v2 tags**: a 2.3 tag at offset 0 holding `TCON = "Drum And Bass;Electronic;Neurofunk"`, and behind it one or two 2.4 tags holding the same three genres separated by nulls. - ATL reads one tag, at offset 0, and never looks past it (`AudioDataManager.cs:531-540`). - lofty merges consecutive ID3v2 tags, later frames replacing earlier ones (`mpeg/read.rs`), so the 2.4 frame answered and three genres came out. Both readers were behaving correctly by their own lights; they simply disagree about how many tags a file has. The reader now hides the second and later front tags from lofty, so it parses the first and then the audio. Of 4889 files in the library, exactly four have stacked tags — the four in this issue — and a sweep of every tag item of every file shows those four are the only ones whose values change at all. Measured against upstream's database: | | rows differing on genre | |---|---| | before | 7 — 4 tracks, 2 album rows, 1 ordering | | after | 1 — the ordering | The issue said four tracks and undercounted: the two Spor album rows carried the same split. The review found a real defect in the fix: a second header claiming a body larger than the file holds pushed the hidden stretch past the end, and the subtraction that removes it underflowed — a panic in debug, a length near `u64::MAX` in release. That is an mp3 whose copy was cut short mid-tag. Guarded, with a test that reproduces the panic without it. A footer is now counted only for 2.3 and 2.4, matching what the reader below believes. What is left is one album, `Enigma/Seven Lives Many Faces (2008)`, whose tracks each agree with upstream exactly but whose album row starts from a different track's genres. That is about the order tracks are folded into an album summary, not about reading tags, and none of its files carry stacked tags. Filed separately as #46.
Sign in to join this conversation.
No description provided.