Skip to content

TUI SIGILL (ud2) in OpenTUI drawTextBuffer when compositor scale jumps to 4 #42094

Description

@dhh

Summary

An idle OpenCode TUI aborts with SIGILL (ud2) the instant the compositor scales the monitor up to 4. This has happened twice, weeks apart, on two OpenCode versions, at the same instruction pointer and on the same second as the scale-to-4 event.

This is not a missing-CPU-feature SIGILL. The faulting instruction is a deliberate ud2 abort in the bundled Bun runtime, reached from OpenTUI's text-buffer draw path.

Same abort site as #41483 (opencode+0x2407064 / libopentui.so+0x1d061d), but a different trigger: a healthy local foot session that had already been running for ~56 minutes, not a partial capability handshake at startup.

What happened

  1. Started opencode --auto in foot on Hyprland (18:38).
  2. Worked in a session, then left the TUI idle (last session write 18:56:40).
  3. Scaled the external display DP-1 from 3.13 → 4.
  4. Kernel recorded the abort on that same second:
Aug 12 19:34:41 traps: opencode[3769384] trap invalid opcode ip:2607064

The process dumped core (si_code: ILL_ILLOPN). No OOM, 37 GiB free.

Reproduction

Reliable on this machine whenever OpenCode's TUI is open and the monitor is scaled to 4.

  1. Hyprland + foot, OpenCode TUI running (opencode --auto is enough; session can be idle).
  2. External display: Apple Pro Display XDR, 6016x3384@60.
  3. Scale DP-1 up through 2 → ~3.13 → 4.
  4. OpenCode dies immediately with SIGILL.

Logical resolution at those scales:

scale logical size
2 3008×1692
3.13 1920×1080
4 1504×846

Going 2 → 3.13 did not kill it. The abort is on the step to 4.

Two hits, same abort, same trigger

when version command scale event (same second)
2026-08-04 19:27:23 CEST 1.18.11 opencode --auto DP-1 3.20 → 4
2026-08-12 19:34:41 CEST 1.18.16 opencode --auto DP-1 3.13 → 4

Both cores have identical offsets:

#0  opencode + 0x2407064     ; ud2
#1  opencode + 0x2405266
#2  opencode + 0x32dd8bf     ; napi_internal_suppress_crash_on_abort_if_desired
#3  opencode + 0x44e35ad
#4  libc.so.6 + 0x3e6f0      ; __restore_rt
#5  libopentui.so + 0x1d061d

That is the same #0/#5 pair reported in #41483.

Symbolized OpenTUI frame

libopentui.so is still on disk (/tmp/.9adb5cbffaf2ed8f-00000000.so, not stripped, has DWARF). addr2line on frame #5:

buffer.OptimizedBuffer.trySetTransparentTextCellFast
  packages/core/src/zig/buffer.zig:896

called from:
  OptimizedBuffer.drawTextBufferInternal   buffer.zig:1659
  OptimizedBuffer.drawTextBuffer           buffer.zig:1274
  lib.bufferDrawTextBufferView             lib.zig:2521

The instruction at that offset is a cell-buffer load inside the fast path (cmpl $0xff, (%rsi,%rcx,4)), not a SIMD op.

Faulting bytes in the main binary:

260705f:  call   0x2634e80     ; noreturn abort helper
2607064:  ud2                  ; <- RIP
2607066:  int3 int3 int3 ...

Classic Zig/Bun "noreturn returned" / panic abort, which the kernel reports as trap invalid opcode.

Inference (not proven)

Scale 3.13 → 4 shrinks the logical viewport by ~22% and delivers a SIGWINCH / TIOCSWINSZ to foot. OpenTUI then redraws. trySetTransparentTextCellFast indexes self.buffer.char[index] with no bounds check; OptimizedBuffer.resize reallocs those arrays. A draw that still holds an index computed against the pre-resize width/height would trip a Zig safety panic, which becomes this ud2.

I have not single-stepped the panic reason (no panic string in the journal). The timestamp match + the symbolized draw path is the evidence.

Ruled out

  • OOM / resource exhaustion
  • AVX / "baseline binary on old CPU" (Intel Core Ultra X7 358H, avx2+; the opcode is ud2, not EVEX)
  • A crash in the herdr OpenCode plugin — it is installed, but it is not on the crashing stack
  • --auto itself (that is just how the agent is launched; the abort is in the renderer)

Environment

  • opencode 1.18.16 (previous hit: 1.18.11), installed via mise
  • Bun v1.3.14 (Linux x64 baseline), bundled
  • OpenTUI native libopentui.so extracted to /tmp/.9adb5cbffaf2ed8f-00000000.so
  • OS Arch Linux, kernel 7.1.5-arch1-1-ptl, glibc 2.44
  • compositor Hyprland 0.56.2
  • terminal foot 1.27.0, JetBrainsMono Nerd Font 9
  • display Apple Pro Display XDR DP-1 6016×3384@60
  • CPU Intel Core Ultra X7 358H

Expected

A compositor scale change (or any SIGWINCH / resize) should reflow the TUI. It should not abort the process.

Workaround

Do not scale the monitor to 4 while OpenCode is open, or close OpenCode first. Session data in ~/.local/share/opencode/opencode.db survived; the crash was during an idle redraw.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions