Skip to content

Fix: Memory leaks in core components#8716

Merged
vadi2 merged 5 commits intoMudlet:developmentfrom
mpconley:fix/core-memory-leaks
Dec 29, 2025
Merged

Fix: Memory leaks in core components#8716
vadi2 merged 5 commits intoMudlet:developmentfrom
mpconley:fix/core-memory-leaks

Conversation

@mpconley
Copy link
Copy Markdown
Contributor

@mpconley mpconley commented Dec 28, 2025

Brief overview of PR changes/additions

This PR fixes three memory leaks in Mudlet's core components that were causing gradual memory growth during extended sessions:

  • Trigger Editor: Fixed 96KB leak per editor session by transferring auto-complete provider ownership to Edbee via giveProvider()
  • Profile Management: Fixed 272-byte leak per profile load/unload by properly cleaning up QKeySequence shortcuts
  • Discord Integration: Fixed 48-byte leak on shutdown by moving event handler cleanup outside conditional block

Motivation for adding to Mudlet

These memory leaks were causing Mudlet to gradually consume more memory over time, particularly noticeable during extended play sessions. The fixes prevent unnecessary memory growth and improve overall application stability.

Other info (issues closed, discussion etc)

  • All changes maintain Qt6/C++20 compatibility
  • The auto-complete provider ownership is transferred to Edbee via giveProvider(), which handles cleanup automatically at app shutdown
  • Changes have been tested with successful builds on macOS

Based off of logs message.txt message_1.txt from this Discord discussion.

- Fix dlgTriggerEditor StringTextAutoCompleteProvider leak (96KB per session)
  * Add proper destructor with removeProvider() cleanup
  * Add member variable to track auto-complete provider instance
  * Include proper edbee textautocompleteprovider header
- Fix Host QKeySequence leak (272 bytes per profile load)
  * Add qDeleteAll(profileShortcuts) cleanup in destructor
- Fix Discord event handlers memory leak (48 bytes per shutdown)
  * Add explicit mpHandlers cleanup in destructor
- Convert per-editor auto-complete provider to shared static instance
- Add reference counting to track editor instances
- Only initialize provider once and clean up when last editor closes
- Prevents use-after-free and ownership conflicts with multiple editors
- Fixes issue where closing one editor would clobber another's provider
- Remove unnecessary explicit disconnect calls (Qt auto-disconnects)
@mpconley mpconley requested a review from a team as a code owner December 28, 2025 23:53
@add-deployment-links
Copy link
Copy Markdown

add-deployment-links bot commented Dec 28, 2025

Hey there! Thanks for helping Mudlet improve. 🌟

Test versions

You can directly test the changes here:

No need to install anything - just unzip and run.
Let us know if it works well, and if it doesn't, please give details.

@vadi2
Copy link
Copy Markdown
Member

vadi2 commented Dec 29, 2025

Thanks for tackling these memory leaks!

A couple of suggestions:

discord.cpp: The mpHandlers deletion is inside if (mLoaded), but it's allocated unconditionally at line 100. If the library fails to load after allocation, it will leak. Consider moving the cleanup outside that block, or making the allocation conditional too.

dlgTriggerEditor: There's a simpler approach that avoids manual reference counting entirely. The edbee library has giveProvider() which transfers ownership - cleanup happens automatically at shutdown:

// In constructor - no destructor needed
static bool sAutoCompleteInitialized = false;
if (!sAutoCompleteInitialized) {
    auto* provider = new edbee::StringTextAutoCompleteProvider();
    // ... populate provider ...
    
    // Transfer ownership to Edbee - deleted automatically at app shutdown
    edbee::Edbee::instance()->autoCompleteProviderList()->giveProvider(provider);
    sAutoCompleteInitialized = true;
}

This eliminates the static ref counter, custom destructor, and parent provider cleanup. The provider stays in memory until app exit, but it's just autocomplete strings so that's fine.

Host.cpp looks good 👍

- discord.cpp: Move mpHandlers cleanup outside if(mLoaded) block
  * Handlers are allocated unconditionally, so cleanup should be too
  * Prevents potential leak if Discord library fails to load after allocation

- dlgTriggerEditor: Simplify auto-complete provider using giveProvider()
  * Use edbee's giveProvider() to transfer ownership to library
  * Provider is automatically deleted at app shutdown
  * Eliminates manual reference counting and custom destructor
  * Replaces smSharedAutoCompleteProvider/smAutoCompleteProviderRefCount
    with simple smAutoCompleteInitialized boolean flag
@mpconley
Copy link
Copy Markdown
Contributor Author

Done

Copy link
Copy Markdown
Member

@vadi2 vadi2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good now, it's just a few KB of savings in a profile but anything is welcome.

The LLM added a few obvious comments, think a pass on removing those to make the code easier to read for humans would be good 👍

Minor code cleanup:
- Remove duplicate explanatory comments about memory ownership
- Clean up whitespace in Host destructor
@vadi2 vadi2 enabled auto-merge (squash) December 29, 2025 17:21
@vadi2 vadi2 merged commit cfd225c into Mudlet:development Dec 29, 2025
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