You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ruvllm: GgufFile panics or misreads tensor data on a malformed alignment or tensor offset #1202
Issue opened by an AI agent on behalf of @ohdearquant.
What happens
ruvllm::gguf::GgufFile uses two header values without checking them, so a malformed GGUF file can crash the caller or return the wrong tensor data instead of an error.
general.alignment = 0.GgufFile::open panics with attempt to divide by zero in align_offset (crates/ruvllm/src/gguf/mod.rs:799), in debug and release builds.
general.alignment stored as a u64 holding u64::MAX. A debug build panics with attempt to add with overflow on the same line. A release build wraps and sets the data section offset to 0, so open succeeds and load_tensor_f32 returns the file's first four bytes (the GGUF magic, 13649.819 as an f32) as the tensor's value.
A tensor offset past the end of the file. Through GgufFile::open the read fails cleanly (Failed to read tensor: failed to fill whole buffer). Through GgufFile::open_mmap it panics with range start index 4224 out of range for slice of length 132 (mod.rs:575): read_tensor_bytes slices the in-memory copy without a bounds check. That line is the default build's variant; the mmap feature's variant on line 573 slices the same way.
open_mmap calls open first, so cases 1 and 2 reach it as well.
Reproduction
At main31549f7, Linux x86_64, rustc 1.98.0, default features. This script writes five small GGUF v3 files, each with one F32 tensor holding 1.0:
Output, summarized (each call is wrapped in catch_unwind):
File
debug, open
debug, open_mmap
release, open
release, open_mmap
valid32.gguf (alignment 32)
[1.0]
[1.0]
[1.0]
[1.0]
valid-default.gguf (no alignment key)
[1.0]
[1.0]
[1.0]
[1.0]
zero.gguf (alignment 0)
panic: divide by zero
panic: divide by zero
panic: divide by zero
panic: divide by zero
max-u64.gguf (u64 alignment u64::MAX)
panic: add with overflow
panic: add with overflow
[13649.819]
[13649.819]
offset-past-eof.gguf (tensor offset 4096)
Err: failed to fill whole buffer
panic: range start index 4224 out of range for slice of length 132
Err: failed to fill whole buffer
panic: range start index 4224 out of range for slice of length 132
Expected
An Err for each malformed file, as the reader already returns for other header problems such as an unsupported version. For comparison, llama.cpp's reader (ggml/src/gguf.cpp at f2cc7282) refuses a general.alignment that is not a u32, and refuses a value that is zero or not a power of two.
Suggested fix
After parsing metadata, require general.alignment to be a non-zero power of two and return RuvLLMError::Model otherwise.
In read_tensor_bytes, compute data_offset + offset + byte_size with checked arithmetic and compare it with the data length before slicing, so the in-memory path returns an error as the file path already does.
We can open a pull request with tests for these cases if that would help.
Activity
fix(ruvllm): refuse malformed GGUF alignment and tensor ranges (#1204)
ruvnet commentedon Oct 24, 2026
Fixed by #1204.