es-ude / es-ude/OnDeviceTraining

tensor: ASYM int-repr dequant codes[i] + zeroPoint can overflow int32 for far-from-zero positive grids

Open
#384 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.