#### Brief overview of PR changes/additions
- `61c2afd40` (#9712) made `$XDG_CONFIG_HOME/mudlet/profiles` the opt-in
marker for an isolated config root, and an empty
`$XDG_CONFIG_HOME/mudlet` no longer qualifies. It updated three
functional tests to the new recipe and missed two, so
`ProfileDeletionSafetyTest` and `ConnectionDialogCrashTest` resolved to
the real `~/.config/mudlet` and failed in `initTestCase()` on every leg
(run 31428353403). Every open PR inherits that red, because PR builds
merge the dev tip.
- Both now pre-create `mudlet/profiles`, matching the ten sibling tests
and `src/mudlet-lua/tests/README.md`. Product code is untouched.
- An empty `profiles/` still reads as a fresh install
(`anyProfilesExist()` counts subdirectories), so neither test's
first-launch expectations move.
Test case: `ctest -R
"ProfileDeletionSafetyTest|ConnectionDialogCrashTest"` against a
`~/.config/mudlet` that holds profiles - both fail on `development`,
both pass here; the full functional suite is otherwise unchanged.
Assisted-by: Claude:claude-opus-5
#### Brief overview of PR changes/additions
- **Right-clicking the games list with nothing selected killed Mudlet.**
`dlgConnectionProfiles::slot_profileContextMenu()` dereferenced
`currentItem()` unguarded. That line is byte-identical in 4.22.0, so the
null deref itself is long-standing and latent - what is new is that it
became reachable: "improve: split the games list into My games and All
games tabs" (#9452) leaves a user with no saved profiles an empty but
still right-clickable "My games" tab, a state 4.22.0's always-populated
list never had. About 40 seconds into a fresh install.
- **Copying a profile while the list was rebuilt was a use-after-free.**
The copy runs on a thread pool and its completion handler kept the
`QListWidgetItem*` it had made; clicking the other games tab meanwhile
calls `fillout_form()`, which destroys every item. The handler now finds
the copy by name, and the `QFutureWatcher` is parented so it cannot
outlive the dialog.
- **Quitting before the connection dialog had been shown dereferenced
null.** The queued `0ms` lambda in `mudlet::slot_showConnectionDialog()`
used `mpConnectionDialog`, which `mudlet::closeEvent()` closes (it is
`WA_DeleteOnClose`) and clears.
#### Motivation for adding to Mudlet
All three came out of the 5.0 QA sweep and are confirmed with
AddressSanitizer. The first is the serious one - it is the default state
of a brand-new install, so a new user can lose Mudlet before they have
connected to anything.
Scope note on the third: it is **not** a 5.0 regression. It has been
there since "Fix: Improve tab indicators and detached window UX" (#7965)
and is unchanged in 4.22.0; #9493 only turned the literal `0` into
`0ms`. Nor could I reach it by clicking: I drove *Games -> Close
profile* followed by quitting at six delays from 0 to 2000 ms and the
dialog was always painted first. It reproduces deterministically
in-process, and QA reproduced it 2/2 driving the close from Lua. Worth
guarding - the pointer is documented to go null - but latent rather than
routinely hit.
#### Other info (issues closed, discussion etc)
Test case: `ctest -R ConnectionDialogCrashTest` - with the fix reverted,
four of its tests reproduce the original ASan reports exactly (two SEGVs
in `slot_profileContextMenu`, a heap-use-after-free in
`slot_itemClicked`, the SEGV in `QWidget::show()` from the lambda); two
more are controls that pass either way, one of them pinning that the
menu still opens for a selected profile so the guard cannot degenerate
into an unconditional early return. Full suite 79/79.
Assisted-by: Claude:claude-opus-5