#2431·conky

[Bug]: wayland: segfault on resize when cairo produces an invalid (nil) surface

Author: sniper1720Created Aug 13, 2026Updated Aug 13, 2026
Labelsbugtriage

What happened?

I run conky desktop widgets on KDE Plasma (Wayland), and the process started crashing with SIGSEGV — usually during a resize or redraw, but once even while the widget sat idle after an earlier resize. I dug into the coredump and found a null-pointer dereference of data->pool in window_allocate_buffer(). This crash escapes every existing guard in the buffer path, so I don't think it's rare.

Reproduction

Intermittent, but I saw it three times in one session, at different PIDs. The first crash was on first run, right when a missing Lua module left the text metrics in a bad state. After fixing the module it crashed again anyway — which is how I knew the bug lives at the allocation site, not in the Lua path.

Root cause (confirmed via coredump, PID 4008)

The whole chain, step by step:

  1. window_resize() calls window_allocate_buffer().
  2. create_shm_surface_from_pool() calls cairo_image_surface_create_for_data() with the (scaled) width/height.
  3. If a dimension is ≤ 0, cairo doesn't return an error — it hands back its special nil surface with CAIRO_STATUS_INVALID_SIZE.
  4. cairo_surface_set_user_data() fails on a nil surface (you can't attach user data to one), so data never gets attached.
  5. Back in window_allocate_buffer(), cairo_surface_get_user_data() returns NULL, and the code dereferences it at data->pool = (i == 1) ? pool : nullptr;.

Why the existing guard can't catch it: window_allocate_buffer() only checks if (!window->shm_surface[i]), and the nil surface is a non-NULL pointer. Worse, the shm allocation can succeed with garbage dimensions — when both scaled dimensions are negative, stride = -1 but length = (-1) × (negative) = positive, so shm_pool_allocate() returns a valid mapping and the nil surface is built on top of it.

Expected behavior

A bad resize should never crash conky. It should log the problem, keep the last good frame, and retry on the next update — exactly what the Weston clients/window.c code this path was ported from does.

Proposed direction

Validate the buffer right at the allocation site: reject stride < 0 and length <= 0 before mapping, check cairo_surface_status() after surface creation, and check cairo_surface_set_user_data()'s return value. On any failure, return NULL so the existing !window->shm_surface[i] guard destroys the pool and keeps the previous buffers.

References

  • cairo manual: cairo_surface_set_user_data, cairo_surface_status (nil surfaces → CAIRO_STATUS_INVALID_SIZE).
  • Weston clients/window.c: the buffer-management code this was ported from.

Related existing reports

  • #1791 (closed) — a different Wayland crash (wl_dispatch race, fixed via #2198); different stack, not this NULL-deref.
  • #1824 (closed) — another Wayland crash, reverted via #2104; also unrelated.
  • cc1dc5d fix(wayland): fix output scale race condition — fixed a pending_scale race whose garbage scaling is a plausible trigger of the invalid dimensions landing in this resize path. Citing as context, not a fix for the dereference itself.

I didn't find any open issue or PR covering the nil-surface NULL-deref in window_allocate_buffer().

Version

conky git master (Wayland build, as of 1affe0297 / June 2026), compiled with -DBUILD_WAYLAND=ON -DBUILD_LUA_CAIRO=ON -DBUILD_LUA_TEXT=ON.

Which OS/distro are you seeing the problem on?

Arch Linux

Conky config

lua
conky.config = {
    own_window = true,
    own_window_type = 'desktop',
    -- rendered via wlr-layer-shell on Wayland
}


The full config is a Lua Cairo dashboard (`own_window_type = 'desktop'`); I can attach it if needed.

Stack trace

gdb
Paste of the coredump forensics (systemd-coredump, PID 4008):


Program terminated with signal SIGSEGV, Segmentation fault.
#0  window_allocate_buffer (window=0x...) at src/output/display-wayland.cc:1304
    movq $0x0,0x8(%rax)        # write to 0x8 == data->pool, with rax == 0 (data == NULL)
Backtrace:
  #0  window_allocate_buffer
  #1  window_resize
  #2  display_output_wayland::main_loop_wait
  #3  main_loop
  #4  main


The cairo surface at fault symbolises as `_cairo_surface_nil_invalid_size`, i.e. `CAIRO_STATUS_INVALID_SIZE`. Struct layout confirms the write target: `buffer@0, pool@8, busy@16`.

Relevant log output

bash
# conky's own log at crash time (this path was only logging normal draw activity):
[info ] [src/display-wayland.cc] window resized ...
# systemd-coredump captured SIGSEGV for PID 4008, backtrace as above.


I can share the full coredump on request.