Skip to content

zuid: host_to_net/net_to_host assume Mac is big-endian, but Mac hasn't been since the 2006 Intel transition #157

Description

@sean-parent

Location

adobe/implementation/zuid_sys_dep.hpp:103-115:

// NOTE (SRP) : From the HP man pages for these functions they swap between
// host and network byte order (I think it is going little to big endian).
// Mac is big endian so just NOP them.

#if ADOBE_PLATFORM_MAC

// Any other platforms that are Big Endian should use this code as well

template <typename I> // where I models a BinaryInteger
inline I host_to_net(I host) {
    return host;
}

template <typename I> // where I models a BinaryInteger
inline I net_to_host(I net) {
    return net;
}

#else
// ... swab(x) ...
#endif

ADOBE_PLATFORM_MAC is defined unconditionally to 1 on Apple platforms (adobe/config.hpp.in:56) — it does not check architecture or endianness. This comment was true on 68k/PowerPC Macs, but every Mac since the 2006 Intel transition (and every Apple Silicon Mac since 2020) is little-endian, same as Windows/Linux x86/ARM. So on all currently-shipping and all historically-Intel Mac hardware, this branch is taking the wrong code path: it should be swapping bytes (like the #else branch does), but instead it's a no-op.

Concrete impact

Both functions are used in source/zuid_uuid.cpp:

  • Name-based UUIDs (v3/v5)uuid_create_from_name, source/zuid_uuid.cpp:183-189: the namespace ID is explicitly converted to network byte order before MD5-hashing it with the name, with the comment "put name space ID in network byte order so it hashes the same no matter what endian machine we're on." Because host_to_net no-ops on Mac, the bytes fed into the hash on Mac are in host (little-endian) order rather than network (big-endian) order — the opposite of what happens on Windows/Linux (which correctly swap via swab). Name-based UUIDs generated on a modern Mac for a given namespace+name will not match the UUID generated for the same inputs on Windows/Linux, defeating the whole point of normalizing to network byte order.

  • Time-based UUIDs (v1)uuid_create, source/zuid_uuid.cpp:74-79: the freshly-generated UUID's multi-byte fields are converted from network to host order for the in-memory/local representation. On Mac this no-ops, so data1_m/data2_m/data3_m end up in the wrong byte order relative to spec — this can affect field comparisons, ordering, and string serialization of the UUID.

Why this hasn't been caught

Both bugs are internally self-consistent within a single Mac build (generate wrong, read back wrong, get the same answer), so nothing observably breaks unless you compare/exchange UUIDs across platforms, or against the reference OSF DCE / RFC 4122 test vectors. It's been latent since the original Intel transition (~2006).

Open question (ramifications of fixing)

This bug has been present for essentially the entire lifetime of Mac OS X on Intel/Apple Silicon (~20 years), so any Mac-only deployment relying on deterministic name-based UUID generation (same namespace+name → same UUID) has been getting consistent — but spec-non-compliant and cross-platform-incompatible — results. Correcting the endian check (e.g. keying off actual byte order, such as std::endian::native in C++20, rather than ADOBE_PLATFORM_MAC) would change the UUIDs produced by uuid_create_from_name on Mac going forward. Filing this primarily to track the bug and discuss whether/how to land the fix safely (e.g. versioning, migration notes for anything that persisted Mac-generated name-based UUIDs expecting stability).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions