Skip to content

fix(#50): getInt/decodeCount reject stored values longer than 8 bytes - #65

Merged
s2x merged 1 commit into
masterfrom
fix/issue-50-getint-decode-truncation
Jul 4, 2026
Merged

fix(#50): getInt/decodeCount reject stored values longer than 8 bytes#65
s2x merged 1 commit into
masterfrom
fix/issue-50-getint-decode-truncation

Conversation

@s2x

@s2x s2x commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #50

Problem

ReadTransaction::getInt() and HighContentionAllocator::decodeCount() silently truncated stored values larger than 8 bytes via unpack('P'), which reads only the first 8 bytes. A malformed or oversized stored value was misread without any error — a wrong integer could be returned for any data that was not actual little-endian-packed 8 bytes.

Fix

Both decoders now explicitly check the stored length and throw a clear RuntimeException when it exceeds 8 bytes, instead of silently returning a wrong value.

  • New ReadTransaction::decodeLittleEndianInt() (protected static) centralizes the bounds-checked decode; getInt() delegates to it.
  • HighContentionAllocator::decodeCount() gets the same explicit length guard with the same exception semantics.

Acceptance Criteria

  • Documentation updated — docs/atomic-operations.md describes the > 8-byte -> RuntimeException behavior.
  • Changelog entry added — under [Unreleased] / Fixed referencing [[Bug] getInt/decodeCount silently truncate values longer than 8 bytes #50].
  • Unit tests added — new tests/Unit/IntDecodeTest.php covers boundary cases for both helpers (empty, 1, 4, 8, max-uint64, 9-byte, 100-byte). 339/339 unit tests pass (12 new).
  • Functional tests added — tests/Integration/DatabaseConvenienceTest gains getIntRoundTripsViaAtomicAdd (atomic add + getInt end-to-end), getIntRejectsOversizedStoredValue, and getIntReadBreakdownBySizeCases.
  • composer test end-to-end pass — unit tests run locally; integration suite requires the docker FDB cluster (CI).

Quality gate

composer lint (PHPCS + Rector + PHPStan level 9) — green.
composer test:unit — 339/339 pass, 654 assertions.

Previously, both ReadTransaction::getInt() and HighContentionAllocator::decodeCount()
silently truncated values larger than 8 bytes via unpack('P'), which reads only
the first 8 bytes. A malformed or oversized stored value returned a wrong integer
without any error.

Now both methods throw a clear RuntimeException describing the actual stored
length when it exceeds the 8-byte little-endian integer contract.

Changes:
- Extract a testable protected static helper decodeLittleEndianInt() on
  ReadTransaction that performs the bounds check; getInt() delegates to it.
- decodeCount() in HighContentionAllocator gains the same explicit length
  guard with the same exception semantics.
- New IntDecodeTest covers boundaries: empty, 1, 4, 8, max uint64, >8 (rejected),
  long input (rejected), both helpers.
- New integration tests in DatabaseConvenienceTest:
  * getIntRoundTripsViaAtomicAdd — atomic add then getInt
  * getIntRejectsOversizedStoredValue — oversize value throws
  * getIntReadBreakdownBySizeCases — 1/4/8-byte raw packs decode correctly
- CHANGELOG and docs/atomic-operations.md updated.
@s2x
s2x merged commit 0bb10f3 into master Jul 4, 2026
6 checks passed
@s2x
s2x deleted the fix/issue-50-getint-decode-truncation branch July 4, 2026 12:48
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.

[Bug] getInt/decodeCount silently truncate values longer than 8 bytes

1 participant