Skip to content

Fix legacy 64-bit OCD layout detection on big-endian platforms - #1472

Merged
frankslin merged 1 commit into
BYVoid:masterfrom
frankslin:fix-issue-1471
Aug 4, 2026
Merged

frankslin merged 1 commit into
BYVoid:masterfrom
frankslin:fix-issue-1471

Conversation

@frankslin

Copy link
Copy Markdown
Collaborator

Fixes #1471.

Problem

The BinaryDict and DartsDict deserializers detect the legacy 64-bit OCD layout by checking whether probe bytes [4..7] are all zero. That assumes the high half of a native uint64_t sits at bytes [4..7], which is only true on little-endian hosts. On big-endian platforms (s390x, ppc64, sparc64, hppa) the high half is at bytes [0..3], so a legacy file is always misdetected as fixed-width: the first uint32_t read picks up the zero high half, numItems/dartsSize come out as 0, and the dictionary silently loads as empty. This is what breaks the five legacy-layout tests on Debian's big-endian buildds.

Fix

Replace the byte-offset idiom at all three sites (BinaryDict.cpp DetectFieldWidth, DartsDict.cpp NewFromFile and NewFromBuffer) with a shared LooksLikeLegacy64Field() helper in the private header BinaryDict.hpp: load the 8-byte probe as a native uint64_t via memcpy and check (word >> 32) == 0. Since legacy files are written in native byte order by construction, a native load recovers the original value on either byte order:

  • Little-endian: word >> 32 is exactly bytes [4..7] — identical to the current behavior, zero change.
  • Big-endian: a legacy field loads back to its true value with zero high bits; a fixed-width file's high half is the first uint32 field (numItems/dartsSize), non-zero for any non-empty dictionary. The empty-dictionary corner case is already excluded by the existing size != 3 * sizeof(uint32_t) guard.

No changes to the legacy read paths themselves (ReadField, LegacyUnit64, ValidateLegacy64) — those already do native loads of natively-written data. Legacy .ocd files remain same-byte-order-only by construction; .ocd2 is unaffected.

Verification

  • arm64 (little-endian): //src:binary_dict_test and //src:darts_dict_test pass via Bazel, 22/22 before and after.
  • s390x (big-endian, QEMU user emulation, Debian Sid, CMake build): BinaryDictTest 10/10 and DartsDictTest 12/12 pass, including the five tests failing on the Debian buildds (AcceptsLegacy64BitLayout, RejectsHugeValueTotalLength, LoadsLegacy64bitFormat, Legacy64PrefixSearchBeyond64Matches, Legacy64SerializeToFileThrows). The test fixtures are generated at runtime with native writes, so they exercise the real big-endian legacy layout.

@hosiet a confirmation run on a real Debian porterbox would still be welcome.

The BinaryDict and DartsDict deserializers detected the legacy 64-bit
layout by checking whether probe bytes [4..7] are zero, which only holds
on little-endian hosts; on big-endian platforms (s390x, ppc64, sparc64,
hppa) legacy files were misread as fixed-width and loaded as empty
dictionaries. Replace the byte-offset idiom at all three sites with a
shared LooksLikeLegacy64Field() helper that loads the probe as a native
uint64_t and checks its high 32 bits, which is correct on both byte
orders and compiles to the same behavior on little-endian. Verified with
BinaryDictTest and DartsDictTest on arm64 and on emulated s390x.

Fixes BYVoid#1471
@frankslin
frankslin merged commit 8aeb5e6 into BYVoid:master Aug 4, 2026
41 checks passed
@frankslin
frankslin deleted the fix-issue-1471 branch August 4, 2026 20:31
@hosiet

hosiet commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Tests on Debian side can confirm things to be working. Thanks!

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.

Legacy 64-bit dictionary layout is misdetected on big-endian platforms (v1.4.x regression)

2 participants