Skip to content

gui: fix the ImGui assertion when creating a recovery phrase - #118

Merged
Bitflash-sh merged 1 commit into
mainfrom
gui-finish-enddisabled
Aug 3, 2026
Merged

gui: fix the ImGui assertion when creating a recovery phrase#118
Bitflash-sh merged 1 commit into
mainfrom
gui-finish-enddisabled

Conversation

@Bitflash-sh

Copy link
Copy Markdown
Owner

The bug

Creating a recovery phrase from the window aborts with an ImGui assertion, on the success path:

Program: Bitflash.exe
File: imgui/imgui.cpp    Line: 8435
Expression: (g.DisabledStackSize > 0) && "Calling EndDisabled() too many times!"

DrawCreatePhraseDialog guards the Finish button with a BeginDisabled/EndDisabled pair, and the button's own handler mutates the condition that guards it:

if (!g_phraseWrittenDown)
    ImGui::BeginDisabled();          // not called: the box is ticked
if (ImGui::Button("Finish", ...))
{
    ...
    g_phraseWrittenDown = false;     // flips the condition
    ...
}
if (!g_phraseWrittenDown)
    ImGui::EndDisabled();            // now called, with nothing to close

The pair is opened while the checkbox is ticked and closed after the handler has unticked it. Tick the box and press Finish — the only path that installs a seed — and ImGui asserts.

This has been there since the phrase UI shipped in 1.2.12, through three releases, because nothing in the test suite touches the window.

The fix

Read the condition once, into a local, before the button that changes it. The restore dialog next door (DrawRestorePhraseDialog) already does exactly this with its fBusy flag; this makes the create dialog match.

Testing

mingw32-make -f makefile.mingw tests in MSYS2 UCRT64: builds clean, all five self-tests pass.

Then the test that actually mattered, driving the real window on Windows 11 with Mesa llvmpipe — Wallet Safety → Create recovery phrase → tick the box → Finish:

  • Published 1.2.14 binary (control): assertion raised, identical to the report.
  • This build: no assertion. The dialog closes, Wallet Safety reports "This wallet has a recovery phrase", the status line reads "Recovery phrase created. New addresses come from it.", and the address on the main window changes to a derived one.

Notes for anyone who hits this on a running wallet

The seed is installed before the assertion fires — SetHDSeedFromMnemonic runs earlier in the same handler — so the phrase on screen is the wallet's real phrase and the wallet is not left half-installed.

Answering Ignore is safe. The macro is IM_ASSERT_USER_ERROR_RET, which returns before touching DisabledStackSize, so no ImGui state is corrupted and the window carries on. Abort is not safe: it kills the process with no DBFlush, which is how a wallet.dat becomes unopenable (#40).

Creating a recovery phrase from the window aborted with an ImGui
assertion on the success path:

  Expression: (g.DisabledStackSize > 0) && "Calling EndDisabled() too many times!"
  File: imgui/imgui.cpp  Line: 8435

The Finish button is wrapped in BeginDisabled/EndDisabled guarded by
!g_phraseWrittenDown, and its own click handler sets g_phraseWrittenDown
to false. So the pair was opened while the checkbox was ticked and
closed after the handler had unticked it: BeginDisabled was never
called, EndDisabled was, and ImGui asserted on the unmatched close.

It fires on the only path that installs a seed -- tick the box, press
Finish -- so every phrase created from the window has hit it since the
feature shipped in 1.2.12. Three releases carried it because nothing
tests the window.

Reproduced on the published 1.2.14 binary and confirmed fixed on this
build, driving the real window: Wallet Safety -> Create recovery phrase
-> tick -> Finish. The old build raises the assertion; the fixed build
closes the dialog, reports "This wallet has a recovery phrase", and the
address changes to a derived one.

The seed itself was already written before the assertion, so the wallet
was never left half-installed -- and ImGui's IM_ASSERT_USER_ERROR_RET
returns before touching its state, so answering Ignore was safe. Abort
was not: it kills the process with no DBFlush.

The restore dialog next door already does this correctly, copying the
condition into a local first. This makes the create dialog match.
@Bitflash-sh
Bitflash-sh merged commit c260974 into main Aug 3, 2026
@Bitflash-sh
Bitflash-sh deleted the gui-finish-enddisabled branch August 3, 2026 13:33
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