Summary
Using text.NewMultiFace with a primary font + fallback fonts leads to a nil pointer dereference inside the GPU text path when DrawString is called.
The panic happens on the render thread:
runtime error: invalid memory address or nil pointer dereference
github.com/gogpu/gg/text.(*FontSource).copyCheck
github.com/gogpu/gg/text.(*FontSource).Parsed
github.com/gogpu/gg/internal/gpu.(*GlyphMaskEngine).LayoutText
github.com/gogpu/gg/internal/gpu.(*GPURenderContext).DrawGlyphMaskText
github.com/gogpu/gg.(*Context).tryGPUGlyphMaskText
github.com/gogpu/gg.(*Context).DrawString
Environment
- gg v0.50.11
- gogpu v0.50.2
- Linux + Vulkan (Intel HD Graphics 520)
- Go 1.26
Reproduction
- Load a primary monospace font (
UbuntuMono-R.ttf).
- Load one or more fallback fonts (Noto Sans CJK / Noto Color Emoji etc.).
- Create
text.NewMultiFace(primary, fallbacks...).
- Set it on a
gg.Context and call DrawString (any non-ASCII character is enough to trigger it in our case).
Using only the primary face works fine.
Metrics() and Advance() on the MultiFace also succeed — the nil appears only later inside the GPU GlyphMask engine.
Notes
- The same set of fonts works correctly when used through the X11 backend (via
golang.org/x/image/font).
- A simple feature probe that only calls
Metrics() / Advance() is not sufficient to detect the bad MultiFace.
- Current workaround on our side: always return the primary face for the gogpu backend and disable MultiFace.
Expected behaviour
text.MultiFace should be usable with the GPU text path the same way a single FontSource.Face is. A nil *FontSource should never reach Parsed / copyCheck.
Summary
Using
text.NewMultiFacewith a primary font + fallback fonts leads to a nil pointer dereference inside the GPU text path whenDrawStringis called.The panic happens on the render thread:
Environment
Reproduction
UbuntuMono-R.ttf).text.NewMultiFace(primary, fallbacks...).gg.Contextand callDrawString(any non-ASCII character is enough to trigger it in our case).Using only the primary face works fine.
Metrics()andAdvance()on the MultiFace also succeed — the nil appears only later inside the GPU GlyphMask engine.Notes
golang.org/x/image/font).Metrics()/Advance()is not sufficient to detect the bad MultiFace.Expected behaviour
text.MultiFaceshould be usable with the GPU text path the same way a singleFontSource.Faceis. A nil*FontSourceshould never reachParsed/copyCheck.