Skip to content

fix(blob): #516 - fix 32-bit truncation in BLOB ID round-trip + legacy compat#555

Merged
satwareAG-ironMike merged 1 commit into
satware-mainfrom
fix/blob-id-32bit-truncation
Jul 20, 2026
Merged

fix(blob): #516 - fix 32-bit truncation in BLOB ID round-trip + legacy compat#555
satwareAG-ironMike merged 1 commit into
satware-mainfrom
fix/blob-id-32bit-truncation

Conversation

@satwareAG-ironMike

Copy link
Copy Markdown

Summary

Two critical bugs found by code review before v13.0.1 release. Both cause silent data corruption for BLOB IDs with low > 0xFFFF.

Bug 1: _php_fbird_string_to_quad truncates 32-bit low part to 16 bits

fbird_blobs.c:225: cast was (ISC_USHORT)low_part — truncates 32-bit ISC_ULONG to 16 bits. The #516 fix changed the variable type and sscanf format but forgot to update the cast on the assignment line.

// Before (broken — truncates to 16 bits):
qd->gds_quad_low = (ISC_USHORT)low_part;

// After (correct — full 32-bit):
qd->gds_quad_low = (ISC_ULONG)low_part;

Bug 2: BlobId::fromString() drops lower 16 bits of hex-format input

src/Firebird/BlobId.php:140: substr($hex, 8, 4) reads only 4 hex digits (16 bits) instead of 8 (32 bits). The #516 fix changed the output format (%08X) but not the input parsing. Test blessed the buggy output.

// Before (broken — drops lower 16 bits):
$low = hexdec(substr($hex, 8, 4));  // 2345 from abcdef0123456789

// After (correct — full 32 bits):
$low = hexdec(substr($hex, 8, 8));  // 23456789 from abcdef0123456789

Issue 3: Procedural binding rejects 13-char BLOB IDs (asymmetric with OOP)

fbird_query_bind.c:929/1043, fbird_batch.c:560/741 used exact Z_STRLEN_P != BLOB_ID_LEN (17) check, rejecting legacy 13-char IDs from v13.0.0. Users upgrading could not bind stored 13-char IDs — silently treated as blob content (data corruption).

Fix: Accept both BLOB_ID_LEN (17) and BLOB_ID_LEN_LEGACY (13). _php_fbird_string_to_quad() already parses both via %x:%x.

ISC_QUAD structure (verified across FB3/FB4/FB5)

gds_quad_high: ISC_LONG  (32-bit signed)
gds_quad_low:  ISC_ULONG (32-bit unsigned)

17-char format (8+1+8 hex) is correct for ALL Firebird versions (3.0, 4.0, 5.0+).

Cosmetic fixes

  • fbird_batch.c:554: removed duplicate comment block + stale 13-char example
  • BlobId.php: updated stale docblocks (13→17 char format)
  • php_fbird_includes.h: added BLOB_ID_LEN_LEGACY constant

Verification

CI-exact environment (php:8.4-cli-bookworm + official FB4 tarball):

  • tests/blobid_001.phpt PASS (FB4 + FB5)
  • tests/003.phpt PASS (FB4 + FB5)
  • tests/issue119.phpt PASS
  • tests/issue307_trans_start_nullable_options.phpt PASS
  • tests/transaction_default_slot.phpt PASS

Found by: v13.0.1 release readiness code review

…y compat

Two critical bugs found by code review before v13.0.1 release:

## Bug 1: _php_fbird_string_to_quad truncates 32-bit low part to 16 bits

fbird_blobs.c:225: cast was (ISC_USHORT)low_part — truncates 32-bit
ISC_ULONG to 16 bits. The #516 fix changed the variable type and
sscanf format but forgot to update the cast on the assignment line.

Fix: (ISC_ULONG)low_part (matches gds_quad_low type in types_pub.h:195)

## Bug 2: BlobId::fromString() drops lower 16 bits of hex-format input

src/Firebird/BlobId.php:140: substr($hex, 8, 4) reads only 4 hex
digits (16 bits) instead of 8 (32 bits). The #516 fix changed the
output format (%08X) but not the input parsing. Test blessed the
buggy output.

Fix: substr($hex, 8, 8) + update test expectation.

## Issue 3: Procedural binding rejects 13-char BLOB IDs (asymmetric)

fbird_query_bind.c:929/1043, fbird_batch.c:560/741 used exact
Z_STRLEN_P != BLOB_ID_LEN (17) check, rejecting legacy 13-char IDs
from v13.0.0. Users upgrading could not bind stored 13-char IDs —
silently treated as blob content (data corruption).

Fix: Accept both BLOB_ID_LEN (17) and BLOB_ID_LEN_LEGACY (13).
_php_fbird_string_to_quad() already parses both via %x:%x.

## Cosmetic fixes

- fbird_batch.c:554: removed duplicate comment block + stale example
- BlobId.php: updated stale docblocks (13→17 char format)
- php_fbird_includes.h: added BLOB_ID_LEN_LEGACY constant

## ISC_QUAD structure (verified across FB3/FB4/FB5)

gds_quad_high: ISC_LONG (32-bit signed)
gds_quad_low:  ISC_ULONG (32-bit unsigned)
→ 17-char format (8+1+8 hex) is correct for ALL Firebird versions

## Verified on CI-exact environment

- php:8.4-cli-bookworm + official FB4 tarball
- firebirdsql/firebird:4 + firebirdsql/firebird:5 servers
- tests/blobid_001.phpt PASS (FB4 + FB5)
- tests/003.phpt PASS (FB4 + FB5)
- tests/issue119.phpt PASS
- tests/issue307_trans_start_nullable_options.phpt PASS
- tests/transaction_default_slot.phpt PASS

Found by: v13.0.1 release readiness code review
@satwareAG-ironMike
satwareAG-ironMike merged commit fa04a29 into satware-main Jul 20, 2026
61 of 62 checks passed
@satwareAG-ironMike
satwareAG-ironMike deleted the fix/blob-id-32bit-truncation branch July 20, 2026 09:53
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.

1 participant