Skip to content

Stop the first run hanging on the language list#64

Merged
xroche merged 2 commits into
masterfrom
fix-firstrun-language-hang
Jul 26, 2026
Merged

Stop the first run hanging on the language list#64
xroche merged 2 commits into
masterfrom
fix-firstrun-language-hang

Conversation

@xroche

@xroche xroche commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Every clean install currently hangs on launch and has to be killed.

LANGINTKEY() returns "" and never NULL, so an index naming no language yielded an empty name, and that empty name is what ends the enumeration loop in Cabout::OnInitDialog. Making the guard live in 5345d2d turned the miss into a "???" placeholder instead, three characters long, so the loop never ends: it AddString()s into the combo box forever, one core pinned and no message pump.

The About box is shown on the first run only, gated on Interface\FirstRun, and that flag is written before the modal opens. So the first launch hangs, killing it leaves the flag set, and every later run skips the block and behaves perfectly. That is why this survived five days and a release build: it reproduces exactly once per machine, and only on a machine nobody has run it on before.

The fix hands back the empty name that LANGINTKEY() already produces, and states the contract at the declaration. The self-heal 5345d2d was actually for, falling back to English on a stale index, is untouched.

--selftest now walks the list under a sane bound and fails rather than hanging, and CI asserts the check ran. Nothing else in CI could see this: --selftest exits long before any dialog, so the hang was invisible to every green build, including the one that shipped it.

Found while VM-testing #61, which turned out to be innocent: the same freeze reproduces on master at 099041c without it.

xroche and others added 2 commits July 26, 2026 09:47
LANGINTKEY() returns "" and never NULL, so an index naming no language yielded
an empty name, and that empty name is what ends the enumeration loop in
Cabout::OnInitDialog. Making the guard live in 5345d2d turned the miss into a
"???" placeholder instead, three characters long, so the loop never ends: it
AddString()s into the combo box forever, one core pinned, no message pump.

The About box is shown on the first run only, gated on Interface\FirstRun, and
that flag is written to the registry BEFORE the modal opens. So a clean install
hangs on launch, killing it leaves the flag set, and every later run skips the
block and looks fine. That is why it survived: it reproduces once per machine.

Hand back the empty name, which is what LANGINTKEY() already produces, and state
the contract at the declaration so it does not get "fixed" a third time. The
self-heal that 5345d2d was actually for, falling back to English on a stale
index, is untouched.

--selftest now walks the list under a sane bound and fails instead of hanging,
and CI asserts the check ran. Nothing else in CI can see this: --selftest exits
long before any dialog, so the hang was invisible to every green build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HXNEMWtyrkW7xoD8ewcR3
Signed-off-by: Xavier Roche <roche@httrack.com>
The assertion accepted "after 0 entries", so a lang.def that loaded with no
language keys would have passed it while proving nothing. Require at least one.

The same contract was also spelled out four times over; keep it at the
declaration and let the other three sites point at it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HXNEMWtyrkW7xoD8ewcR3
Signed-off-by: Xavier Roche <roche@httrack.com>
@xroche
xroche merged commit 73b7cd7 into master Jul 26, 2026
3 checks passed
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