sys.path.insert(0, str(Path(__file__).parent.parent))
from gguf.constants import (
+ GGML_MAX_DIMS,
GGML_QUANT_SIZES,
GGUF_DEFAULT_ALIGNMENT,
GGUF_MAGIC,
# Get Tensor Dimensions Count
n_dims = self._get(offs, np.uint32)
offs += int(n_dims.nbytes)
+ if n_dims[0] > GGML_MAX_DIMS:
+ raise ValueError(f'Tensor dimensions count {n_dims[0]} exceeds GGML_MAX_DIMS ({GGML_MAX_DIMS})')
# Get Tensor Dimension Array
dims = self._get(offs, np.uint64, n_dims[0])
raise ValueError(f'Found duplicated tensor with name {tensor_name}')
tensor_names.add(tensor_name)
ggml_type = GGMLQuantizationType(raw_dtype[0])
- n_elems = int(np.prod(dims))
+ # use Python ints: np.prod on uint64 wraps silently on overflow
+ n_elems = 1
+ for dim in dims.tolist():
+ n_elems *= int(dim)
np_dims = tuple(reversed(dims.tolist()))
block_size, type_size = GGML_QUANT_SIZES[ggml_type]
n_bytes = n_elems * type_size // block_size
--- /dev/null
+import struct
+import numpy as np
+import pytest
+
+from gguf.gguf_reader import GGUFReader
+
+
+def _write_gguf(path, n_dims_field, dims):
+ buf = b'GGUF' + struct.pack('<IQQ', 3, 1, 0) # version 3, 1 tensor, 0 kv
+ name = b'bad_tensor'
+ buf += struct.pack('<Q', len(name)) + name
+ buf += struct.pack('<I', n_dims_field)
+ for d in dims:
+ buf += struct.pack('<Q', d)
+ buf += struct.pack('<I', 0) # dtype F32
+ buf += struct.pack('<Q', 0) # tensor offset
+ buf += b'\x00' * 64
+ path.write_bytes(buf)
+
+
+def test_n_dims_upper_bound(tmp_path):
+ # crafted file claims 1_000_000 dims; must be rejected, not read past EOF
+ p = tmp_path / 'evil_ndims.gguf'
+ _write_gguf(p, 1_000_000, [1] * 8)
+ with pytest.raises(ValueError, match='exceeds GGML_MAX_DIMS'):
+ GGUFReader(p)
+
+
+def test_dims_product_no_uint64_wraparound(tmp_path):
+ # dims whose true product overflows uint64; np.prod would wrap to 4 and
+ # silently pass an undersized read. The reader must not accept it.
+ dims = [4194305, 4194305, 211106198978564]
+ assert int(np.prod(np.array(dims, dtype=np.uint64))) == 4 # the wrap bug
+ p = tmp_path / 'evil_overflow.gguf'
+ _write_gguf(p, len(dims), dims)
+ with pytest.raises(ValueError):
+ GGUFReader(p)