1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
# Patches to the vendored libghostty-vt
D12 vendors libghostty-vt pinned by commit, "with a patches file if we ever
need one". This is that file.
Patches are applied **to the vendored tree in this repository**, which is
committed, so a normal `make vendor` build already has them. The `.patch`
files here exist for provenance: they say what we changed, why, and what has
to be re-applied when the vendored version is bumped. `vendor/*.vendor.json`
lists them under `patches`.
Re-vendoring is therefore: drop in the new upstream tree, apply each patch in
order, resolve anything that has moved, rebuild, run `make test`.
`contrib/vendor-check` says when that is worth doing: it compares the pin in
`vendor/*.vendor.json` against upstream and lists the commits touching the
terminal core, so watching upstream is one command rather than a browser tab.
`ship` mentions it after every release.
## 0001 — keep kitty images across a screen clear
`Terminal.eraseDisplay` called `kitty_images.delete(..., .{ .all = true })`
for both `ED 2` and `ED 3`, where the `true` means "and free the image data
for anything no longer placed".
The kitty graphics protocol separates *transmitting* an image (`a=t`, which
stores it under an id) from *placing* it (`a=p`, which puts it on screen), so
that a program can upload once and place many times — that is the whole point
of having two verbs, and the reason the delete command distinguishes `d=a`
(placements) from `d=A` (placements and data). Freeing the data on a screen
clear breaks it: any full-screen program that clears and redraws loses every
image it uploaded, and every later placement of that id draws nothing at all.
Found with a bouncing-DVD screensaver that transmits ten frames up front and
then places one per frame. It works in kitty; under us it drew nothing, and
the reason was three layers down.
The patch removes only the freeing. Placements on the cleared screen still go
— clearing the screen should clear what is on it — and the image store still
bounds itself the way it always did, with a 320MB limit and LRU eviction on
insert, which is exactly the mechanism that makes keeping them safe.
Worth sending upstream.
## 0002 — don't export weak `calloc`/`free` from the static library
`pkg/wuffs/src/main.zig` exported weak, hidden `calloc`/`free` stubs whenever
`!builtin.link_libc`. `callocStub` returns `null` unconditionally. They exist
because wuffs' generated `wuffs_foo__bar__alloc()` helpers are the only code
referencing libc's allocator, we never call them, and linker GC *usually*
strips them — the stubs are there in case it doesn't.
The comment says "weak so that any real definition wins". That holds when the
real definition comes from a shared libc, but not from a static archive: once
the linker pulls this member in for some other symbol, the weak `calloc` here
*satisfies* the reference, so it never searches `libc.a` for musl's strong
one. Every `calloc` in the consuming program then returns `NULL`, and `free`
becomes a no-op.
We only hit this in the browser demo, which is the one build that has to pass
`-Dsimd=false` (highway emits RVV intrinsics that do not compile for rv64gc),
and `GhosttyZig.zig` sets `link_libc = if (cfg.simd) true else null` — so the
demo's library is the only one of ours built without libc, and the guest links
it statically against musl. The symptom was `slosh: cannot start session main`
in the demo: the first `calloc` in `kdl.c:node_new` returned `NULL` and the
store into it faulted, which killed the session server before its socket
existed. The host build (libc linked, stubs never exported) was unaffected,
which is why every test on this machine passed.
The patch adds `and builtin.output_mode == .Exe`. The stubs still do their job
in a final link with no libc, and a library — whose consumer is the thing that
owns the choice of allocator — no longer interposes on it. `web/demo/boot-check`
is the regression test; it caught this in twenty seconds once it was run.
Worth sending upstream.
|