Repository navigation
fix(launch_manager): make IdentifierHash stable across compilers/binaries - #527
Merged
MaciejKaszynski merged 7 commits intoAug 28, 2026
Conversation
hskang-amelia
requested review from
FScholPer,
MaciejKaszynski,
NicolasFussberger,
anmittag,
antonkri,
pawelrutkaq and
ramceb
as code owners
August 26, 2026 07:12
hskang-amelia
had a problem deploying
to
workflow-approval
August 26, 2026 07:12 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 26, 2026 07:12 — with
GitHub Actions
Failure
Contributor
License Check Results🚀 The license check job ran with the Bazel command: bazel run --lockfile_mode=error //:license-checkStatus: Click to expand output |
hskang-amelia
force-pushed
the
fix/create-transition-invalid-graph-index
branch
from
August 26, 2026 07:18
75b0f90 to
859abff
Compare
hskang-amelia
had a problem deploying
to
workflow-approval
August 26, 2026 07:19 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 26, 2026 07:19 — with
GitHub Actions
Failure
hskang-amelia
marked this pull request as draft
August 26, 2026 07:26
MaciejKaszynski
requested changes
Aug 26, 2026
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 01:20 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 01:20 — with
GitHub Actions
Failure
hskang-amelia
marked this pull request as ready for review
August 27, 2026 01:59
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 02:02 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 02:02 — with
GitHub Actions
Failure
…ries
IdentifierHash used std::hash<std::string>/std::hash<std::string_view>,
which is standard-library-implementation-defined. This works fine within
a single process, but IdentifierHash's actual job — being sent as a raw
hash over ControlClient IPC to Launch Manager, with no string attached —
depends on it producing the identical value regardless of which compiler
or libstdc++/libc++ version built the caller. It didn't: a run target
name hashed by a ControlClient built with a different toolchain than
Launch Manager itself produced a different numeric hash for the exact
same string.
The practical effect: Launch Manager's own Graph::startTransition()
looks up that hash in its run_targets_ map, finds nothing
(getRunTargetIndex returns -1), and passes the resulting -1 through a
debug-only assert (compiled out in a release build) straight into
TransitionBuilder::createTransition(), which then aborts the whole
daemon on its own always-on assert (transition_.isValidNode(target)) —
turning an ordinary "unrecognized run target" into a full crash instead
of a graceful ControlClientCode::kSetStateInvalidArguments response.
Root-caused with an independent ControlClient implementation driving a
live Launch Manager instance, built by a different toolchain than
Launch Manager itself: it requested activation of the exact run target
Launch Manager had already activated as its `initial_run_target` on
boot — same string, and Launch Manager's own IdentifierHash::operator<<
diagnostic showed two different hash values for it once instrumented.
Switches to FNV-1a (a fixed, portable algorithm with no dependency on
the standard library's hash implementation) and adds a regression test
pinning specific expected hash values, so any future change to the
algorithm has to consciously re-examine the cross-binary guarantee
IdentifierHash exists to provide. Selects offset/prime constants
matching the width of std::size_t so this also holds on 32-bit
architectures, and adds a std::hash<IdentifierHash> specialization
delegating to IdentifierHash::data(), so the class can be used as an
unordered_map/unordered_set key without a custom hasher.
identifier_hash.cpp's own long-standing comment already flagged this
exact risk ("if this should work between different compilers, we may
need to go for our own hash function") — this resolves that open
question with evidence.
Verified end to end: with this fix, the same independent ControlClient
successfully drove a live launch_manager instance through its initial
transition and a subsequent run target switch (ActivateRunTarget
returning Success), both of which previously either killed the daemon
via this assert.
hskang-amelia
force-pushed
the
fix/create-transition-invalid-graph-index
branch
from
August 27, 2026 02:05
ababff5 to
5222639
Compare
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 02:05 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 02:05 — with
GitHub Actions
Failure
Contributor
Author
|
Hi @MaciejKaszynski,
Also re-verified end to end against a live Launch Manager (both the initial activation of |
Contributor
Author
|
Applied via the suggested commit (84838a6) — thanks! |
MaciejKaszynski
previously approved these changes
Aug 27, 2026
danth
suggested changes
Aug 27, 2026
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 09:15 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 09:15 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 09:20 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 09:20 — with
GitHub Actions
Failure
…ten IdentifierHash test coverage FNV-1a constants now cover exactly 32-bit and 64-bit std::size_t via #if/#elif, and fail to compile (#error) on any other width instead of silently reusing the 64-bit constants. Corrects the stability regression test's description: it pins values computed independently of this codebase but only runs on one target, so passing it does not by itself demonstrate cross-target stability. Adds the remaining string_view/const char* comparison to the constructor-overload test.
hskang-amelia
force-pushed
the
fix/create-transition-invalid-graph-index
branch
from
August 27, 2026 09:27
cf2bb78 to
173fe15
Compare
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 09:27 — with
GitHub Actions
Failure
hskang-amelia
had a problem deploying
to
workflow-approval
August 27, 2026 09:27 — with
GitHub Actions
Failure
MaciejKaszynski
approved these changes
Aug 28, 2026
danth
approved these changes
Aug 28, 2026
Merged
2 of 3 tasks
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
IdentifierHashusesstd::hash<std::string>/std::hash<std::string_view>, which is standard-library-implementation-defined — deterministic within one binary's execution, but not guaranteed stable across different compilers or libstdc++/libc++ versions. That's a problem specifically becauseIdentifierHash's primary real-world use is being sent as a raw numeric hash overControlClientIPC to Launch Manager — no string travels with it, so the two sides must compute the identical value independently. If theControlClientside and the Launch Manager daemon happen to be built by different toolchains, they don't.Effect:
Graph::startTransition()looks the incoming hash up inrun_targets_, gets-1(getRunTargetIndex), and that-1slips past aSCORE_LANGUAGE_FUTURECPP_ASSERT_DBG_MESSAGE(compiled out in a release build) straight intoTransitionBuilder::createTransition(), which then hits its own always-on assert (transition_.isValidNode(target)) and aborts the entire Launch Manager daemon — for what should just be an ordinaryControlClientCode::kSetStateInvalidArgumentsresponse to one bad request.How this was found: building a real cross-toolchain end-to-end reproduction — an independent
ControlClientimplementation, built by a different toolchain than Launch Manager itself, calledActivateRunTarget()for the exact run target name Launch Manager had itself just activated asinitial_run_targeton boot. InstrumentingIdentifierHash::operator<<andGraph::getRunTargetIndexshowed two different numeric hashes for that identical string, one per binary.Fix: switch to FNV-1a (a small, fixed, self-contained algorithm — no dependency on the standard library's hash implementation), and add a regression test that pins specific expected hash values for known input strings, so any future change to the algorithm has to consciously revisit the cross-binary guarantee this class exists to provide.
identifier_hash.cpp's own comment already flagged exactly this risk ("if this should work between different compilers, we may need to go for our own hash function") — this resolves that open question with evidence rather than leaving it as a caveat.Also drops the now-unused
<functional>include.Related ticket
closes #528
Test plan
identifier_hash_UT.cpptests: hardcoded expected FNV-1a values (computed independently of this codebase) for known strings, and cross-constructor-overload consistency (std::string/std::string_view/const char*must agree)bazel test //score/launch_manager/src/daemon/src/common:identifier_hash_UT— passesbazel test //score/launch_manager/...(28/28 targets) — passes, no regressions from the algorithm changeControlClientimplementation against this fix (via a local Bazel module override) and re-ran the exact cross-toolchain repro that originally surfaced this —ActivateRunTarget()now returnsSuccessfor both the initial-transition-to-an-already-active-target case and an actual run target switch, where it previously crashed the daemon every timeNote
Independent of this fix,
createTransition()aborting the entire daemon on any unrecognized run target name (not just this hash-mismatch case) is a separate robustness gap — filed as #541, kept this PR scoped to the actual root cause.