Skip to content

fix(v3/linux): use g_bytes_new instead of g_bytes_new_static for Go slices#4923

Merged
leaanthony merged 4 commits into
wailsapp:v3-alphafrom
ddmoney420:fix/4864-gbytes-gc-safety
Feb 2, 2026
Merged

fix(v3/linux): use g_bytes_new instead of g_bytes_new_static for Go slices#4923
leaanthony merged 4 commits into
wailsapp:v3-alphafrom
ddmoney420:fix/4864-gbytes-gc-safety

Conversation

@ddmoney420

@ddmoney420 ddmoney420 commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace g_bytes_new_static with g_bytes_new for all Go slice data
  • Fix memory leak in setIcon() by adding proper cleanup
  • Add gBytesNew binding to purego implementation

Problem

g_bytes_new_static is documented as expecting "static" data that is never freed or moved. However, the Linux code was passing Go slice data (&icon[0], &img.Pix[0]) which can be moved or freed by Go's garbage collector at any time.

When Go's GC runs, the memory passed to GTK becomes invalid, causing a SIGSEGV crash in g_application_run (the GTK event loop).

From the GLib docs:

g_bytes_new_static: Creates a new GBytes from static data. data must be static (ie: never modified or freed).

Solution

Use g_bytes_new instead, which copies the data to C-owned memory that is safe from Go's GC.

// Before (unsafe - Go memory can be GC'd)
gbytes := C.g_bytes_new_static(C.gconstpointer(unsafe.Pointer(&icon[0])), ...)

// After (safe - data is copied to C memory)
gbytes := C.g_bytes_new(C.gconstpointer(unsafe.Pointer(&icon[0])), ...)

Changes

File Change
linux_cgo.go Replace g_bytes_new_staticg_bytes_new (4 places)
linux_cgo.go Add defer C.g_bytes_unref(gbytes) and defer C.g_object_unref(stream) in setIcon()
linux_purego.go Add gBytesNew function binding
linux_purego.go Replace gBytesNewStaticgBytesNew

Test plan

  • Code compiles on macOS (build tags prevent Linux code from compiling)
  • Manual test on Linux with array parameters

Note: The correlation with "array parameters" in the original issue is likely because array-heavy operations increase memory pressure, triggering GC more frequently and exposing this race condition faster.

Fixes #4864

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed potential crash when focusing a destroyed window on Linux.
    • Prevented a panic when an empty icon/bitmap is provided on Linux.
  • Improvements

    • Improved memory and resource handling for graphics on Linux, enhancing stability and preventing memory-related issues with icons and images.

ddmoney420 and others added 2 commits January 29, 2026 00:38
The Focus() method was missing a nil/destroyed check on w.impl,
causing a SIGSEGV when Focus() is called on a window that has been
hidden and potentially destroyed (e.g., when clicking the dock icon
after hiding the window on macOS).

This aligns Focus() with Show() and Hide() which already have proper
guards against nil/destroyed window implementations.

Fixes wailsapp#4890

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

g_bytes_new_static expects truly static data that is never freed or
moved, but Go's garbage collector can move or free slice memory at any
time. This causes SIGSEGV crashes in the GTK event loop when the GC
runs and frees memory that GTK still references.

The fix replaces g_bytes_new_static with g_bytes_new, which copies the
data to C-owned memory that is safe from Go's GC.

Also fixes memory leak in setIcon() by adding proper g_bytes_unref and
g_object_unref calls for the GBytes and stream objects.

Changes:
- linux_cgo.go: Replace g_bytes_new_static with g_bytes_new (4 places)
- linux_cgo.go: Add cleanup in setIcon() for gbytes and stream
- linux_purego.go: Add gBytesNew binding and use it instead of static

Fixes wailsapp#4864

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

coderabbitai Bot commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Replaced static GBytes usage with dynamic GBytes allocations and added explicit unref/defer calls to ensure C memory isn't tied to Go GC; added guards to avoid creating bytes for empty images; registered a new gBytesNew pointer in pure-Go path; added a nil/destroyed check in WebviewWindow.Focus; updated changelog.

Changes

Cohort / File(s) Summary
GBytes memory & icon handling
v3/pkg/application/linux_cgo.go, v3/pkg/application/linux_purego.go
Replaced g_bytes_new_static(...) usage with g_bytes_new(...) (explicit copy) and added defer C.g_bytes_unref(...) and defer C.g_object_unref(...). Added guards to skip icon/bitmap handling when image data is empty and registered gBytesNew in the pure-Go GTK function table.
Window focus safety
v3/pkg/application/webview_window.go
Added an early return in WebviewWindow.Focus() when the underlying implementation is nil or the window is destroyed to avoid potential panics.
Changelog
v3/UNRELEASED_CHANGELOG.md
Added a bugfix entry noting a potential panic when setting an empty icon/bitmap on Linux.

Sequence Diagram(s)

(Skipped — changes are internal memory-management and small control checks that do not introduce a new multi-component sequential flow.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

go, Linux, v3-alpha

Poem

A rabbit nibbles bytes with care,
Copies saved from GC's snare,
Defer a hop, unref the trail,
Empty icons now skip the tale,
Safe and snug — a hopping cheer! 🐰

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
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.
Description check ❓ Inconclusive The PR description provides a clear summary, explains the problem and solution, lists file changes, and references the linked issue. However, the description template requires specific sections (Type of change checkboxes, How Has This Been Tested, Test Configuration) that are not completed. Complete the PR template sections: check the 'Bug fix' option under Type of change, describe testing performed on Linux, and provide wails doctor output or environment details.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary change: replacing g_bytes_new_static with g_bytes_new for Go slices to fix memory safety issues on Linux.
Linked Issues check ✅ Passed The PR addresses the root cause of issue #4864 by replacing g_bytes_new_static with g_bytes_new to copy Go slice data to C-owned memory, preventing GC-related SIGSEGV crashes during GTK event loop execution.
Out of Scope Changes check ✅ Passed Changes are focused on the memory safety issue and include defensive nil check in WebviewWindow.Focus and changelog update, both of which align with the PR objectives.

✏️ 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: 2

🤖 Fix all issues with AI agents
In `@v3/pkg/application/linux_cgo.go`:
- Around line 665-669: The code takes &slice[0] on icon/bitmap byte slices
(e.g., in linuxApp.setIcon) which will panic for zero-length slices; add a guard
that checks len(icon)==0 (or len(bitmap)==0) and return early (no-op) or handle
as an empty icon before taking &icon[0]; apply the same pattern to the other
similar functions referenced (the blocks at the other occurrences) so you never
call C.g_bytes_new with &slice[0] when the slice is empty.

In `@v3/pkg/application/linux_purego.go`:
- Around line 1196-1200: The code calls
gBytesNew(uintptr(unsafe.Pointer(&img.Pix[0])), len(img.Pix)) without checking
for an empty img.Pix, which can panic; before taking &img.Pix[0] in the
pngToImage success branch, add a guard like if len(img.Pix) == 0 { /* handle
empty icon: skip gBytesNew / set gbytes=nil / use empty buffer */ } else {
gbytes := gBytesNew(uintptr(unsafe.Pointer(&img.Pix[0])), len(img.Pix)) ... } so
pngToImage, img.Pix, and gBytesNew are only used when img.Pix has length > 0.

Comment thread v3/pkg/application/linux_cgo.go
Comment thread v3/pkg/application/linux_purego.go Outdated
Adds guards to check for empty slices before taking &slice[0] which
would panic on empty input. Affects setIcon(), menuItemAddProperties(),
menuItemSetBitmap(), and runQuestionDialog() in both CGO and purego.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@leaanthony leaanthony enabled auto-merge (squash) February 2, 2026 07:44

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
v3/pkg/application/linux_cgo.go (1)

841-858: ⚠️ Potential issue | 🟡 Minor

Unref the temporary GdkPixbuf after creating the GtkImage.
gtk_image_new_from_pixbuf() adds its own reference and does not take ownership, so the local pixBuf must be unref'd to avoid memory leaks. Apply in these three locations.

♻️ Proposed fix (apply to each site)
 pixBuf := C.gdk_pixbuf_new_from_bytes(
 	gbytes,
 	C.GDK_COLORSPACE_RGB,
 	1, // has_alpha
 	8,
 	C.int(img.Bounds().Dx()),
 	C.int(img.Bounds().Dy()),
 	C.int(img.Stride),
 )
 image := C.gtk_image_new_from_pixbuf(pixBuf)
+C.g_object_unref(C.gpointer(pixBuf))
 C.gtk_widget_set_visible((*C.GtkWidget)(image), C.gboolean(1))

Also applies to: 923-940, 2205-2223

@leaanthony leaanthony merged commit 19b2ec7 into wailsapp:v3-alpha Feb 2, 2026
47 of 48 checks passed
@sonarqubecloud

sonarqubecloud Bot commented Feb 2, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
27.6% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Grantmartin2002 pushed a commit to Grantmartin2002/wails that referenced this pull request Apr 29, 2026
…lices (wailsapp#4923)

* fix(v3): add nil check to Focus() to prevent SIGSEGV after Hide

The Focus() method was missing a nil/destroyed check on w.impl,
causing a SIGSEGV when Focus() is called on a window that has been
hidden and potentially destroyed (e.g., when clicking the dock icon
after hiding the window on macOS).

This aligns Focus() with Show() and Hide() which already have proper
guards against nil/destroyed window implementations.

Fixes wailsapp#4890

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

* fix(v3/linux): use g_bytes_new instead of g_bytes_new_static for Go slices

g_bytes_new_static expects truly static data that is never freed or
moved, but Go's garbage collector can move or free slice memory at any
time. This causes SIGSEGV crashes in the GTK event loop when the GC
runs and frees memory that GTK still references.

The fix replaces g_bytes_new_static with g_bytes_new, which copies the
data to C-owned memory that is safe from Go's GC.

Also fixes memory leak in setIcon() by adding proper g_bytes_unref and
g_object_unref calls for the GBytes and stream objects.

Changes:
- linux_cgo.go: Replace g_bytes_new_static with g_bytes_new (4 places)
- linux_cgo.go: Add cleanup in setIcon() for gbytes and stream
- linux_purego.go: Add gBytesNew binding and use it instead of static

Fixes wailsapp#4864

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

* fix(linux): add empty slice guards to prevent panic

Adds guards to check for empty slices before taking &slice[0] which
would panic on empty input. Affects setIcon(), menuItemAddProperties(),
menuItemSetBitmap(), and runQuestionDialog() in both CGO and purego.

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