es-ude / es-ude/OnDeviceTraining
tensor: ASYM int-repr dequant codes[i] + zeroPoint can overflow int32 for far-from-zero positive grids
- Dominant language
- C
- Stars
- 1
- Forks
- 3
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 8
Description
## Problem
The ASYM → INT32 and ASYM → SYM_INT32 converters compute the integer representation as
```c
out[off + i] = codes[i] + inQC->zeroPoint; /* TensorConversion.c:466 and :495 */
```
in **int32 arithmetic**. `codes[i] ∈ [0, 2^qBits − 1]` (qBits ≤ 30 since #246) and `zeroPoint = round(min/scale)` may legitimately sit anywhere in int32 range (#246's pre-round guard in `deriveAsymGridFromMinMax` bounds `round(min/scale)` to int32, but not `round(min/scale) + 2^qBits − 1`). For a **far-from-zero positive band** — `min/scale > INT32_MAX − (2^qBits − 1)` — the sum overflows: signed int32 overflow, UB (C17), same class as #189/#202.
Pre-#246 this was masked by the int16 zeroPoint wrap (the stored zeroPoint was already garbage); the widening made the field correct and thereby **unmasked** the latent sum overflow. Found during the #246 fix (see closing comment there).
The float dequant paths (`(float)codes[i] + (float)zeroPoint`, e.g. :145/:480/:609/:623) sum in float and are not affected.
## Impact / priority
Low — same standing as original #246: ASYM is a partial path with no production caller into the int-repr converters today; the band must be extreme (|values| pushing toward `INT32_MAX·scale`). Filed so the contract is tracked rather than rediscovered.
## Proposed fix
Tighten the #246 pre-round guard in `deriveAsymGridFromMinMax` from “`round(min/scale)` fits int32” to
```
round(min/scale) <= INT32_MAX − (2^qBits − 1)
```
(lower bound unchanged — codes are non-negative, the sum only grows upward). That makes every downstream `code + zeroPoint` int-repr sum safe **by construction**, one line, no per-element cost in the converters.
**Note:** deserialized ASYM configs bypass the derivation guard entirely — the v2 wire (#370) carries an arbitrary i32 zeroPoint. Decide whether `deserializeQConfig` should validate the same bound (fail-fast on load) or whether garbage-in stays out of contract.
## Relations
#246 (unmasked by), #189/#202 (same UB class), #227 (SYM sibling: product overflow).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Contributor guide
Research direction
Read deriveAsymGridFromMinMax and the ASYM int-repr sites in TensorConversion.c at lines 466 and 495. Then inspect deserializeQConfig and the v2 wire format mentioned in #370. Done means the far-from-zero positive case cannot produce an overflowing int32 sum, with deserialized zeroPoint handling decided and covered by tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- machine-learning
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100