uttrflow / uttrflow/uttrflow-swift
A config.json group_size of 0 crashes the suggestion model load with a division by zero
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## What happens
`QuantizedLayerPlan.shapes` divides by the group size read from the model's `config.json`, and nothing checks that value first:
```swift
// Sources/UttrflowLocalModel/QuantizedLayerPlan.swift:63-64
static func shapes(rows: Int, columns: Int, groupSize: Int, bits: Int) -> (weight: [Int], scales: [Int]) {
([rows, columns * bits / 32], [rows, columns / groupSize])
}
```
`QuantizedLoad.build` passes `groupSize` straight from `BaseConfiguration.PerLayerQuantization` (`Sources/UttrflowLocalModel/QuantizedLoad.swift:36-41`). That type decodes `group_size` as a plain `Int` with no range check (mlx-swift-lm `Libraries/MLXLMCommon/BaseConfiguration.swift:28-34, 52`). A cached model whose `config.json` says `"group_size": 0`, globally or for any one layer whose safetensors header has `.scales`, hits Swift's integer division by zero. That traps and takes the app down. It happens when AI suggestions or the local clean-up model load (`MLXCandidateScorer.swift:95`, `MLXCleanupModel.swift:36`), and again on every later load while the file stays in the cache. A negative value gives a negative placeholder shape instead.
This is the same class as #441, which was a safetensors header value trusted into arithmetic. `config.json` comes from the hub download, which is not pinned (#666).
## Why it matters
A bad or tampered model file should give "the model could not be loaded", not a crash that repeats each time the person types, until they find and delete a hidden cache folder.
## How to reproduce
In a copy of a cached suggestion model snapshot, set `quantization.group_size` in `config.json` to `0` and point a load at it (for example a test calling `QuantizedLoad.container(from:using:)`). The process traps in `QuantizedLayerPlan.shapes`.
## Acceptance criteria
- `QuantizedLoad.build` (or `shapes`) accepts a layer only when `groupSize > 0`, `bits` is one MLX supports, and `columns` is divisible by `groupSize`. Otherwise it throws, or skips the placeholder build so the ordinary load reports the error. It never traps.
- A test in `Tests/UttrflowLocalModelTests/QuantizedLayerPlanTests.swift` covers `group_size` 0 and a negative value.
## Where to start
- `Sources/UttrflowLocalModel/QuantizedLoad.swift` and `QuantizedLayerPlan.swift`
- Extend `Tests/UttrflowLocalModelTests/QuantizedLayerPlanTests.swift`
- Run `make verify`. See `CONTRIBUTING.md`.
Size: small (under 30 lines plus tests).
Contributor guide
Research direction
Start with Sources/UttrflowLocalModel/QuantizedLoad.swift and QuantizedLayerPlan.swift, especially the group-size handling and shapes calculation. Extend Tests/UttrflowLocalModelTests/QuantizedLayerPlanTests.swift for zero and negative group_size values, then run make verify. Done means invalid configuration values produce a load error rather than a process trap.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- machine-learning
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 88/100