fix(gguf): parse v2 counts/lengths as uint64 (spec-correct) - #365
fix(gguf): parse v2 counts/lengths as uint64 (spec-correct)#365jamesburton wants to merge 1 commit into
Conversation
GgufReader treated GGUF v2 as if it used uint32 tensor/metadata counts, string lengths and array lengths. Per the GGUF spec the uint32->uint64 switch happened at v1->v2: v2 and v3 are identical on the wire and both use uint64. (v1, the only uint32 form, is rejected by header validation.) Reading a uint32 (4 bytes) where a real v2 file writes a uint64 (8 bytes) misaligns the entire metadata + tensor-info parse. On TheBloke's Llama-2-13B-GGUF (a v2 file) this produced garbage tensor names and offsets, surfacing as a bogus "Tensor '' data extends beyond file boundary" in GgufFile.Open. The bug stayed latent because every model we had tested with was v3, and GgufTestData itself wrote v2 with uint32 — so the writer and reader shared the same wrong assumption and agreed with each other while disagreeing with the spec. Fix: read uint64 for counts, string lengths and array lengths (all supported versions). Fix GgufTestData to write spec-correct uint64 v2 so v2 tests actually exercise the real wire format. Add discriminating regression tests: a full v2 parse (header -> string-array metadata -> tensor infos, where misalignment compounds) and an end-to-end GgufFile.Open v2 case mirroring the Llama-2-13B failure. Verified against the gguf reference library, which parses the same file with uint64. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Polite fortnightly ping 🙂 — status unchanged since opening: the fix parses GGUF v2 counts/string/array lengths as uint64 per the spec (only v1 is uint32), with discriminating v2 regression tests included (the test fixture was co-bugged, which is why this stayed latent). No CI is configured on this branch; the full unit suite passes locally. Happy to rebase or adjust scope if you'd prefer it packaged differently. |
|
Fortnightly ping 🙂 — still open, no changes needed on my side. Recap: GGUF v2 counts / string / array lengths are parsed as uint64 per the spec (only v1 is uint32); every v2 file currently fails to parse. Discriminating v2 regression tests are included — the previous fixture was co-bugged with the reader, which is why this stayed latent while all v3 test models passed. No CI is configured on this branch; the full unit suite passes locally. Happy to rebase, split, or re-scope if that would make it easier to review. |
Closes #364
Problem
Every real GGUF v2 file fails to load with a bogus
InvalidDataException: Tensor '' data extends beyond file boundaryfromGgufFile.Open(observed on TheBloke/Llama-2-13B-GGUF, a v2 file).Root cause
GgufReaderread v2 tensor/metadata counts, string lengths, and array lengths as uint32, treating v2 like the (unsupported) v1 format. Per the GGUF spec theuint32 -> uint64switch happened at v1 -> v2: v2 and v3 are byte-identical on the wire and both use uint64. The buggy pattern in three sites wasversion == 2 ? reader.ReadUInt32() : reader.ReadUInt64()(and the equivalentif (version == 2)branch inReadHeader).Reading 4 bytes where the file wrote 8 misaligns the whole metadata + tensor-info parse, yielding garbage/empty tensor names and offsets — surfacing as the spurious "extends beyond file boundary".
The bug stayed latent because every tested model was v3, and the test fixture
GgufTestDataitself wrote v2 with uint32 — writer and reader shared the same wrong assumption and agreed with each other while both disagreeing with the spec.Fix
src/DotLLM.Models/Gguf/GgufReader.cs— read uint64 for counts, string lengths, and array lengths across all supported versions (v1 is already rejected by header validation), plus accurate doc comments.tests/DotLLM.Tests.Unit/Models/Gguf/GgufTestData.cs— write spec-correct uint64 for v2 so v2 tests exercise the real wire format.tests/.../GgufReaderTests.cs— addReads_V2_FullFile_ArrayMetadataThenTensors_Exactly(header -> string-array metadata -> tensor infos, where misalignment compounds).tests/.../GgufFileTests.cs— addOpen_V2File_WithArrayMetadataAndTensors_Succeeds(end-to-end, mirrors the Llama-2-13B failure).Verification
dotnet test --filter "FullyQualifiedName~Models.Gguf"-> all 73 GGUF tests pass.ggufreference library, which parses the same v2 files with uint64, and confirmed a real Llama-2-13B v2 file loads with the fix.🤖 Generated with Claude Code