Skip to content

Qt client: Drain queued messages before clearing channels - #3426

Merged
bear101 merged 4 commits into
BearWare:masterfrom
computertech1012:fix/channel-tree-stale-events
Sep 14, 2026
Merged

bear101 merged 4 commits into
BearWare:masterfrom
computertech1012:fix/channel-tree-stale-events

Conversation

@computertech1012

@computertech1012 computertech1012 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Hi,

The issue is a Qt client crash during connection loss. A connection-loss message can be handled while the Qt client is draining the SDK message queue, and messages already queued behind it must not be delivered after the channel tree has been cleared.

This now fixes the problem at the disconnect boundary, using the same lifecycle as TeamTalkClassic:

  • Cache the current user settings.
  • Call TT_Disconnect().
  • Drain the remaining TTMessages without dispatching them.
  • Clear the channel tree and the remaining connection UI.

The earlier defensive changes in ChannelsTree have been completely reverted. Its original assertions remain intact, so a genuine invalid widget state still breaks in a Debug build instead of being hidden by release-only guards.

The drain is inside disconnectFromServer(), so it covers connection loss, explicit logout, connection failure, manual disconnect, and shutdown paths. It also terminates the outer polling loop naturally because the SDK queue is empty when control returns.

Validation on the current commit confirms that channelstree.cpp is identical to upstream, that the order is cache, disconnect, drain, reset, and that the implementation matches the established TeamTalkClassic disconnect pattern. The repository's platform builds are also running on the current commit.

@bear101, could you please review the revised approach when you have time? Maintainer edits remain enabled.

Thanks for reading!

@bear101

bear101 commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

What issue are you trying to fix?

@computertech1012

computertech1012 commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Hi,

@bear101 The issue is a Qt client crash when the connection drops while user events are still queued.

The sequence is:

  1. The Qt client starts draining an SDK message batch.
  2. A connection-loss event calls disconnectFromServer(), which resets ChannelsTree and clears its cached users and channels.
  3. A user event that was already queued behind the connection-loss event is still dispatched during the same drain.
  4. On current master, a later user-join event reaches slotUserJoin() after its channel item has been removed. getChannelItem() returns null. A Debug build stops at Q_ASSERT(parent); a Release or RelWithDebInfo build continues into getUserIndex() with the null parent and crashes with 0xC0000005.

Put simply: a connection drop can clear the Qt channel tree before the remainder of the already-queued user events are delivered, and the Qt client currently assumes those tree objects still exist.

This PR does not change SDK event ordering. It makes the Qt UI ignore user events that became stale after its own tree reset. The same defensive handling covers update, leave, and logout events whose cached user or tree item no longer exists.

Unmodified master reproduces the crash using the real MainWindow and ChannelsTree code. With this patch, the same reset/backlog cases and the 250-user, 50-cycle stress test complete without a crash or ghost users. The reproducer has 28 checks and is available in test commit 11c5c86.

The currently failing x86 workflow is TeamTalkStdTestCase.testResampledAudioBlock() in the Java SDK tests; this PR changes only Client/qtTeamTalk/channelstree.cpp.

Thanks for reading!

Comment thread Client/qtTeamTalk/channelstree.cpp
@bear101

bear101 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

The correct approach would be to drain TTMessages after calling TT_Disconnect(). Afterwards the channels tree is cleaned.

@computertech1012 computertech1012 changed the title Qt client. Ignore stale user events after channel reset Qt client: Drain queued messages before clearing channels Sep 10, 2026
@computertech1012

Copy link
Copy Markdown
Contributor Author

Hi,

Thanks, you are right. I was guarding the resulting invalid ChannelsTree state instead of removing the stale SDK messages at the disconnect boundary.

I have now reverted the ChannelsTree guards completely. disconnectFromServer() caches the current users, calls TT_Disconnect(), drains the remaining TTMessages without dispatching them, and only then resets the channel tree. This matches the existing TeamTalkClassic lifecycle and keeps the original Debug assertions intact.

The updated commit is e326b274f. I also verified that channelstree.cpp is now identical to upstream and that the order is cache, disconnect, drain, reset. The platform builds are running on the revised commit now.

Thanks for reading!

Comment thread Client/qtTeamTalk/mainwindow.cpp Outdated
Comment thread Client/qtTeamTalk/mainwindow.cpp Outdated
@computertech1012

Copy link
Copy Markdown
Contributor Author

Hi,

I've updated this in 9785e77. The queued messages now go through processTTMessage() in a shared drainTTMessages() method, called from both TIMER_PROCESS_TTEVENT and disconnectFromServer() before the channel tree is cleared.

I also put TT_Disconnect() back in its original position. Moving it wasn't necessary for this fix. The assertions are unchanged.

The focused source checks pass. I haven't run a full build locally for this revision, so the build results still need to be verified.

Thanks for reading!

@bear101

bear101 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

I'll merge and squash commits

@bear101
bear101 merged commit e553349 into BearWare:master Sep 14, 2026
10 of 12 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.

2 participants