CSI @ (ICH) with an explicit parameter of 0 should be clamped to 1,
matching xterm behavior. Previously, a zero count reached
Terminal.insertBlanks which called clearCells with an empty slice,
triggering an out-of-bounds panic.
Fix the stream dispatch to clamp 0 to 1 via @max, and add a defensive
guard in insertBlanks for count == 0. Found by AFL++ stream fuzzer.
#11109
CSI @ (ICH) with an explicit parameter of 0 should be clamped to 1,
matching xterm behavior. Previously, a zero count reached
Terminal.insertBlanks which called clearCells with an empty slice,
triggering an out-of-bounds panic.
Fix the stream dispatch to clamp 0 to 1 via @max, and add a defensive
guard in insertBlanks for count == 0. Found by AFL++ stream fuzzer.
CSI ? W (cursor tabulation control) accessed input.params[0] without
first checking that params.len > 0, causing an index out-of-bounds panic
when the sequence had an intermediate but no parameters.
Add a params.len == 1 guard before accessing params[0].
Found by AFL++ fuzzing #11109
CSI ? W (cursor tabulation control) accessed input.params[0] without
first checking that params.len > 0, causing an index out-of-bounds
panic when the sequence had an intermediate but no parameters.
Add a params.len == 1 guard before accessing params[0].
Found by AFL++ fuzzing.
If this PR is accepted, it will add a clarification to the contribution
guidelines to inform pre-vouching contributors that they are still
required to apply for vouching as would a first-time contributor.
This adds a `test/fuzz-libghostty` which is a standalone `zig build`
target for building an AFL++ instrumented executable for fuzzing the
libghostty-vt parser. I also added a `pkg/afl++` (based on zig-afl-kit)
so instrumenting objects and using AFL++ is a bit easier.
Fuzzing `libghostty-vt`'s parser is as easy as `zig build run`, but see
the README for a lot more details. I ran the fuzzer for ~14 hours total
and only found one crash #11088. I'm pretty confident at this point our
Parser layer isn't obviously crash-able, but need to instrument more
places to fuzz.
We don't use Zig's built-in fuzzing yet because as of 0.15 (our current
stable), it isn't ready and AFL++ is an industry proven tool to do this.
This fixes a bug in the key state sequence overlay.
## Demo
In my ghostty config, I have
keybind = ctrl+space>escape=ignore
keybind = ctrl+space>p=toggle_command_palette
...
because I use `ctrl+space>` sequences for most things and so hitting
`esc` is my way to bail out of the sequence if I change my mind.
I just switched to tip and got the new GTK key sequence overlay. Here's
what I saw. In these screen recordings, the sequence of keys I press is
ctrl+space, escape, ctrl+space, escape, ctrl+space, escape, ctrl+space,
p
https://github.com/user-attachments/assets/4a37bc7e-b75c-4bd1-99de-f21f4211b5b5
after the fix:
https://github.com/user-attachments/assets/023be88e-1299-4219-920c-1b1134b2888c
## Notes
I believe this was also a leak, since the queued keys wouldn't be
deinited.
**AI usage:** Claude Code suggested the fix, then I read enough code to
convince myself that it makes sense.
When users have something like
[log]
showSignature = true
in their .gitconfig files, invocations of the log or show git
sub-command emit additional information about signatures. This
additional output disturbs the generation of short_hash in
GitVersion.zig, the additional text is copied verbatim into the string
and then shown in the CSI >q output.
To fix it always suppress the output of the signature information. This
has no effects when the setting is disabled anyway.
When users have something like
[log]
showSignature = true
in their .gitconfig files, invocations of the log or show git sub-command
emit additional information about signatures. This additional output
disturbs the generation of short_hash in GitVersion.zig, the additional text
is copied verbatim into the string and then shown in the CSI >q output.
To fix it always suppress the output of the signature information. This
has no effects when the setting is disabled anyway.
When a DCS sequence has more than MAX_PARAMS parameters, entering
dcs_passthrough would write to params[params_idx] without a bounds
check, causing an out-of-bounds access. Add the same guard that
csi_dispatch already has.
Found by AFL fuzzing, test and fix produced by Codex.
When a DCS sequence has more than MAX_PARAMS parameters, entering
dcs_passthrough would write to params[params_idx] without a bounds
check, causing an out-of-bounds access. Drop the entire DCS hook
when params overflow, consistent with how csi_dispatch handles it.
Found by AFL fuzzing.
We haven't used or run these in forever (literally like 3+ years).
They're just wasting cognitive space and confuse some users as to what
they're for. Remove them.
We haven't used or run these in forever (literally like 3+ years).
They're just wasting cognitive space and confuse some users as to what
they're for. Remove them.
I'd like to contribute a fix for an issue I found regarding how macOS
window restoration works when a window is closed via Cmd+W (leaving the
app active).
Currently, the position cascades down and to the right on every reopen,
and size explicitly resets. Also, explicit `window-position-x/y` configs
get ignored on first launch.
I've diagnosed the issues:
1. In `TerminalWindow.swift`, `setInitialWindowPosition` relies on the
`TerminalController` which isn't present during `awakeFromNib`. I moved
the `screen.origin` calculation directly into the window class to ensure
fixed coordinates are respected immediately.
2. In `TerminalController.swift`, I consolidated the window spawning
cascade logic into a new `applyCascade(to:hasFixedPos:)` helper. It now
only calls `cascadeTopLeft` if `TerminalController.all.count > 1`
(meaning another window is active) and fixed coords aren't set. If it's
the only window, it anchors exactly where `LastWindowPosition` placed
it.
3. In `LastWindowPosition.swift`, I updated the `save` and `restore`
logic to persist the full `window.frame` (origin + size) instead of just
the origin.
*Disclosure: I used Cursor (Tab) to assist in navigating the codebase
and formatting the Swift code, but I fully understand the AppKit
lifecycle changes and edge cases I'm proposing.*
I have the commit locally formatted with `swiftlint` and ready to push!