Skip to content

fix(v3/linux): fix OpenFileDialog crash from GTK thread violation#4926

Merged
leaanthony merged 6 commits into
wailsapp:v3-alphafrom
ddmoney420:fix/3683-linux-dialog-crash
Feb 2, 2026
Merged

fix(v3/linux): fix OpenFileDialog crash from GTK thread violation#4926
leaanthony merged 6 commits into
wailsapp:v3-alphafrom
ddmoney420:fix/3683-linux-dialog-crash

Conversation

@ddmoney420

@ddmoney420 ddmoney420 commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes GTK assertion failure and crash when using OpenFileDialog() on Linux.

Problem

When calling OpenFileDialog() on Linux and selecting a file, the application crashed with:

gtk_file_chooser_get_filenames: assertion 'GTK_IS_FILE_CHOOSER (chooser)' failed
signal 11 received but handler not on signal stack

Root Cause

The runChooserDialog function had a race condition and thread safety violation:

  1. InvokeAsync scheduled gtk_dialog_run on the GTK thread
  2. After the dialog closed, a new goroutine was spawned off the GTK thread
  3. gtk_widget_destroy was called immediately (outside InvokeAsync)
  4. The goroutine tried to call gtk_file_chooser_get_filenames on the destroyed widget

GTK is NOT thread-safe - all GTK operations must occur on the GTK main thread.

Solution

  1. Extract filenames on GTK thread BEFORE destroying widget
  2. Call gtk_widget_destroy on GTK thread AFTER extraction
  3. Goroutine only handles sending Go strings (no GTK calls)
InvokeAsync(func() {
    response := C.gtk_dialog_run(...)
    // Extract results on GTK thread
    var results []string
    if response == C.GTK_RESPONSE_ACCEPT {
        filenames := C.gtk_file_chooser_get_filenames(...)
        // ... extract to results slice ...
    }
    // Destroy widget on GTK thread
    C.gtk_widget_destroy(...)
    // Send results from goroutine (safe - no GTK calls)
    go func() {
        for _, result := range results {
            selections <- result
        }
        close(selections)
    }()
})

Test plan

  • Test on Linux with GTK
  • Call OpenFileDialog() from a service binding
  • Select a file and verify no crash occurs
  • Verify selected filename is returned correctly

Fixes #3683

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed a crash on Linux when opening the file chooser by ensuring selected files are collected on the UI thread before the dialog closes, preserving selections reliably and preventing thread-safety issues.

The runChooserDialog function had a race condition that caused GTK
assertion failures and crashes on Linux:

1. InvokeAsync scheduled gtk_dialog_run on the GTK thread
2. After dialog closed, a goroutine was spawned OFF the GTK thread
3. gtk_widget_destroy was called immediately (before goroutine ran)
4. Goroutine tried to call gtk_file_chooser_get_filenames on destroyed widget

Fix:
- Extract filenames on GTK thread BEFORE destroying widget
- Call gtk_widget_destroy on GTK thread AFTER extraction
- Goroutine only handles sending Go strings (no GTK calls)

Fixes wailsapp#3683

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Collect GTK file-chooser results on the GTK thread: retrieve filenames via gtk_file_chooser_get_filenames and buildStringAndFree into a local slice before destroying the widget; the background goroutine iterates that slice and sends selections over the channel (no artificial result cap).

Changes

Cohort / File(s) Summary
GTK File Dialog Thread Safety
v3/pkg/application/linux_cgo.go
Move all GTK calls to the GTK thread: collect filenames with gtk_file_chooser_get_filenames and buildStringAndFree into a local results slice (removed artificial 1024 cap), destroy the widget on the GTK thread, then have the goroutine iterate the local slice to send selections over the channel.
Changelog
v3/UNRELEASED_CHANGELOG.md
Add Fixed entry documenting "Fix OpenFileDialog crash on Linux due to GTK thread safety violation" referencing issue #3683.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

Linux, v3-alpha, size:S, lgtm

Poem

🐰 I hopped onto GTK with careful paws,
Gathered filenames without a pause,
Built each string and freed the rest,
Closed the chooser — now all is best.
Hooray for safe threads and fewer straws! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix: addressing an OpenFileDialog crash on Linux caused by GTK thread safety violations.
Description check ✅ Passed The description covers the problem, root cause, solution, and test plan, but the PR description template checklist items are not explicitly marked as completed in the provided description.
Linked Issues check ✅ Passed The PR directly addresses issue #3683 by ensuring all GTK operations execute on the GTK thread, preventing the assertion failures and crashes from thread safety violations that caused OpenFileDialog to fail.
Out of Scope Changes check ✅ Passed All changes are focused on fixing the GTK thread safety issue in runChooserDialog and documenting the fix in the changelog; no unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@v3/pkg/application/linux_cgo.go`:
- Around line 2109-2129: The loop over filenames from
gtk_file_chooser_get_filenames stops at 1024 and only calls buildStringAndFree
for those items, causing any remaining filename strings to leak because
g_slist_free only frees nodes; modify the extraction logic in the block that
uses filenames, iter and count so you iterate the entire list: for the first up
to 1024 entries call buildStringAndFree and append into results, and for any
remaining entries call C.g_free on the gpointer(iter.data) to free the string;
after finishing the full traversal still call C.g_slist_free(filenames), then
destroy the widget and send results to selections as before (referencing
gtk_file_chooser_get_filenames, buildStringAndFree, C.g_free, C.g_slist_free,
filenames, iter, results, selections).

Comment thread v3/pkg/application/linux_cgo.go

@leaanthony leaanthony left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM! This correctly fixes the GTK thread safety violation. All GTK operations now happen on the GTK thread inside InvokeAsync, and the widget is properly destroyed after extracting results.

The coderabbit comment about the 1024 limit leaking memory is technically valid but a pre-existing edge case (the limit was already there). The main crash fix is correct.

Please add an UNRELEASED_CHANGELOG.md entry for this bug fix.

leaanthony and others added 5 commits February 2, 2026 23:16
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When more than 1024 files are selected, the previous code leaked memory
because g_slist_free() only frees list nodes, not the data pointers.
Now we iterate through ALL entries, freeing each filename string.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
GTK's gtk_file_chooser_get_filenames() has no documented maximum.
The limit was arbitrary and unnecessary.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consistent with Windows/macOS behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Feb 2, 2026

Copy link
Copy Markdown

@leaanthony leaanthony merged commit 1f45359 into wailsapp:v3-alpha Feb 2, 2026
48 checks passed
Grantmartin2002 pushed a commit to Grantmartin2002/wails that referenced this pull request Apr 29, 2026
…ilsapp#4926)

* fix(v3/linux): fix OpenFileDialog crash from GTK thread violation

The runChooserDialog function had a race condition that caused GTK
assertion failures and crashes on Linux:

1. InvokeAsync scheduled gtk_dialog_run on the GTK thread
2. After dialog closed, a goroutine was spawned OFF the GTK thread
3. gtk_widget_destroy was called immediately (before goroutine ran)
4. Goroutine tried to call gtk_file_chooser_get_filenames on destroyed widget

Fix:
- Extract filenames on GTK thread BEFORE destroying widget
- Call gtk_widget_destroy on GTK thread AFTER extraction
- Goroutine only handles sending Go strings (no GTK calls)

Fixes wailsapp#3683

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add changelog entry for OpenFileDialog crash fix

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: properly free all filenames to prevent memory leak

When more than 1024 files are selected, the previous code leaked memory
because g_slist_free() only frees list nodes, not the data pointers.
Now we iterate through ALL entries, freeing each filename string.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: remove arbitrary 1024 file selection limit

GTK's gtk_file_chooser_get_filenames() has no documented maximum.
The limit was arbitrary and unnecessary.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add comment about no file selection limit

Consistent with Windows/macOS behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: ddmoney420 <ddmoney420@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
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