Skip to content

fix(postgres): range-check int64 narrowing on scan - #505

Open
FumingPower3925 wants to merge 1 commit into
mainfrom
fix/postgres-decode-range
Open

fix(postgres): range-check int64 narrowing on scan#505
FumingPower3925 wants to merge 1 commit into
mainfrom
fix/postgres-decode-range

Conversation

@FumingPower3925

Copy link
Copy Markdown
Contributor

What

driver/postgres/pool.go narrowed the decoded int64 into int, int32, int16 and uint32 with a bare conversion in three places:

An out-of-range value (a bigint column scanned into an int32, a negative into a uint32, any 64-bit value into int on a 32-bit build) wrapped silently instead of failing the scan.

This PR adds four small helpers (int64ToInt, int64ToInt32, int64ToInt16, int64ToUint32) that bounds-check against math.MinX/MaxX and return celeris-postgres: scan: value %d out of range for <type> — the scan-side twin of the encoder's existing int4 overflow / int2 overflow rejections — and routes all nine narrowing sites through them. On error the destination is left untouched. The *int guard is a no-op on 64-bit and real on 32-bit, as the issue specifies.

Why

database/sql and the driver's own encode side both treat a value that does not fit as an error; silently returning a wrong number is a correctness bug, and CodeQL go/incorrect-integer-conversion flagged it as a true positive.

Fail-first evidence

New file driver/postgres/decode_range_test.go, run against unfixed main (9a8fc6a) before the fix:

--- FAIL: TestDecodeTextInto_Int32Overflow (0.00s)
    decode_range_test.go:43: expected out-of-range error for int32, got nil
--- FAIL: TestDecodeBinaryInto_Int32Overflow (0.00s)
    decode_range_test.go:93: expected out-of-range error for int32, got nil
--- FAIL: TestDecodeBinaryInto_Int16Overflow (0.00s)
    decode_range_test.go:104: expected out-of-range error for int16, got nil
--- FAIL: TestDecodeBinaryInto_Uint32Overflow (0.00s)
    decode_range_test.go:112: expected out-of-range error for uint32, got nil
FAIL
FAIL	github.com/goceleris/celeris/driver/postgres	0.349s

(the boundary tests already passed on unfixed code, as expected — they pin the min/max values so the guards are not off by one.)

After the fix:

--- PASS: TestDecodeTextInto_Int32Overflow
--- PASS: TestDecodeTextInto_Int32Boundaries
--- PASS: TestDecodeTextInto_IntAndInt64Boundaries
--- PASS: TestDecodeBinaryInto_Int32Overflow
--- PASS: TestDecodeBinaryInto_Int16Overflow
--- PASS: TestDecodeBinaryInto_Uint32Overflow
--- PASS: TestScanValue_IntNarrowingRange
--- PASS: TestDecodeBinaryInto_Boundaries
ok  	github.com/goceleris/celeris/driver/postgres	1.346s   (-race)

Verification

  • gofmt -l driver/postgres/ clean
  • go vet ./... clean, go build ./... clean
  • golangci-lint run ./driver/postgres/... (v2.13.2, go1.27.0): 0 issues
  • go test ./driver/postgres/... -race -count=1: postgres ok (32.9s), protocol ok — all existing decode/scan tests stay green

Fixes #502

decodeTextInto, decodeBinaryInto and scanValue converted the decoded int64 into int / int32 / int16 / uint32 with a bare conversion, so an out-of-range value (e.g. 2147483648 scanned into *int32) wrapped silently instead of failing the scan. Add bounds-checking helpers that return a 'celeris-postgres: scan: value N out of range for <type>' error, mirroring the encoder's int4/int2 overflow checks, and route every narrowing site through them. Destinations are left untouched on error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

postgres: text-decoding narrows int64 to int/int32 without a range check (CodeQL go/incorrect-integer-conversion, pool.go:777,791)

1 participant