Repository navigation
Conversation
Ghostty statically bundles its own copy of fontconfig, and because the resulting binary is a PIE executable built without hiding those symbols, it globally exports ~27 Fc* functions. GTK4/Pango load the system libfontconfig.so.1 into the same process. Due to ELF symbol interposition, calls made from inside libfontconfig.so.1 (and other GTK-side consumers, e.g. glycin's SVG loader per ghostty-org/ghostty discussion #12555) get redirected to Ghostty's bundled copy instead, corrupting state shared between the two fontconfig instances. This causes reproducible SIGSEGV/SIGABRT crashes (double free / invalid free in FcPatternDestroy, FcFontSetDestroy, or segfaults in FcFontSort), most easily triggered by moving a Ghostty window between monitors with different scale factors, which forces a font grid rebuild through fontconfig. Passing -fsys=fontconfig makes Ghostty dynamically link the system fontconfig instead of statically bundling its own, leaving a single fontconfig instance in the process. Verified locally: the resulting binary exports zero Fc* symbols (down from 27), lists libfontconfig.so.1 as a proper NEEDED entry, and no longer crashes under repeated monitor moves that reliably crashed the unpatched build.
|
Thanks for this @maxib0n. Unfortunately this is blocked on a Zig packaging conflict. Currently Ghostty requires Zig 0.15.2 (exact) to build. Fedora does not offer this. I'll look into solving this, but it won't be immediate. |
|
Hello! I'm confirming this issue as well on ghostty-1.3.1-2.fc44 (from this copr, Fedora 44 Workstation, GNOME/Wayland, system fontconfig 2.17.0-4.fc44). Got six SIGSEGV core dumps within ~7 hours, all inside fontconfig frames, matching the symbol-interposition problem this PR fixes. The clearest core shows GTK4 itself calling into the bundled copy: an xdg-desktop-portal settings change => gtk_settings_notify (libgtk-4.so.1) => FcInitReinitialize resolved to an address inside the ghostty executable (the interposed static 2.14.x copy) => FcConfigSetCurrent => FcConfigDestroy => GP fault destroying an FcPattern that points just past the end of a le64.cache-9 mapping created by system fontconfig 2.17. Four more cores are renderer-thread crashes in FcCompare (fcmatch.c:622) during glyph-fallback discovery: three SEGV_MAPERR with si_addr equal to the candidate FcPattern* (in the one of these with a captured mapping excerpt, that address sits in an unmapped hole directly after a cache-9 mapping), the fourth a GP fault on a non-canonical address derived from the same pattern pointer. One more core is a GP fault in free() under FcStrSetDestroy. Both cores where I captured process mappings (the GTK main-thread crash and one FcCompare crash) have the same font directories mmap'd twice — cache-8 (bundled 2.14.x) and cache-9 (system 2.17.0) side by side. Upstream context: this is ghostty-org/ghostty#10432 / discussions #10568 and #12555; the upstream fix (ghostty-org/ghostty#11152, system fontconfig by default on Linux) was merged 2026-03-03 and reverted the next day, so a spec-level -fsys=fontconfig like this PR is currently the only clean fix on Fedora. Would be great to get this merged and rebuilt. I have full anonymized backtraces for all six cores if useful. |
|
Any updates on this? |
Now that ghostty-org/ghostty#12228 is in the next Ghostty release should resolve this. |
|
I hit this independently on Fedora 44 and filed #548 / #549 before spotting this PR — my mistake, #549 is closed as a duplicate of this one. My coredumps match what @maxib0n and @kapuchai describe exactly (GTK4 Two things I found that this PR doesn't currently cover, in case they're useful when it unblocks. fontconfig isn't the only vendored font library colliding. $ for p in Fc FT_ hb_; do echo "$p: $(nm -D --defined-only /usr/bin/ghostty | grep -cE " [TWD] $p")"; done
Fc: 27
FT_: 57
hb_: 518All three are simultaneously linked from $ for p in Fc FT_ hb_; do echo "$p: $(nm -D --defined-only /usr/bin/ghostty | grep -cE " [TWD] $p")"; done
Fc: 0
FT_: 0
hb_: 0
On the Zig blocker — confirming @scottames is right that it's exact, for anyone who assumed if (current_vsn.major != required_vsn.major or
current_vsn.minor != required_vsn.minor or
current_vsn.patch < required_vsn.patch)Major and minor must match exactly, patch is a floor — so 0.15.2 or 0.15.3+, never 0.16.x. Fedora 44 now ships zig 0.16.0, which means Happy to push the three-flag version as a commit here or as a separate PR if that's helpful, or to leave it alone if the plan is to wait for ghostty-org/ghostty#12228 in the next release. One question, since I couldn't find the reasoning: ghostty-org/ghostty#11152 made system fontconfig the Linux default and was reverted a day later. Does anyone know what broke? Worth knowing before a spec-level |
|
Closing in favor of #549 |
Summary
Ghostty statically bundles its own copy of fontconfig. Because the resulting binary is a PIE executable built without hiding those symbols, it globally exports ~27
Fc*functions. GTK4/Pango load the systemlibfontconfig.so.1into the same process, and due to ELF symbol interposition, calls made from insidelibfontconfig.so.1(and other GTK-side consumers, e.g. glycin's SVG loader, see ghostty-org/ghostty#12555) get redirected to Ghostty's bundled copy instead, corrupting state shared between the two fontconfig instances.This causes reproducible
SIGSEGV/SIGABRTcrashes (invalid free inFcPatternDestroy/FcFontSetDestroy, or segfaults inFcFontSort). The easiest reliable trigger is moving a Ghostty window between two monitors with different scale factors, which forces a font grid rebuild through fontconfig (Surface.contentScaleCallback→setFontSize→SharedGridSet.ref→Fontconfig.discover).Passing
-fsys=fontconfigtozig buildmakes Ghostty dynamically link the system fontconfig instead of statically bundling its own, so there's a single fontconfig instance in the process.Verification
On the currently published
ghostty-1.3.1-2.fc44build:8 coredumps collected over the past week, 6 with matching stack traces through
contentScaleCallback → setFontSize → SharedGridSet.ref → FcFontSetDestroy/FcPatternDestroyorFcFontSort.Rebuilt locally with
-fsys=fontconfigadded (same Zig 0.15.2, same build flags otherwise):Ran the patched binary and repeatedly moved the window between the two monitors that reliably crashed the unpatched build (scale 1.25 vs scale 1) — no crash.
Test plan
zig buildsucceeds with-fsys=fontconfigadded (209/209 steps)Fc*symbols vs 27 beforelibfontconfig.so.1is a properNEEDEDentry