zsh-users / zsh-autosuggestions

Fish-like autosuggestions for zsh
MIT License
30.81k stars 1.85k forks source link

Always reset file descriptor after consuming it #630

Closed codicodi closed 11 months ago

codicodi commented 2 years ago

This prevents the request cancelling logic from closing an unrelated fd that happens to reuse the same number.

https://github.com/zsh-users/zsh-autosuggestions/blob/a411ef3e0992d4839f0732ebeb9823024afaaaa8/src/async.zsh#L12-L15

ericfreese commented 11 months ago

Hey, thanks for this. I stumbled across the same issue while looking into #753 (see last paragraph of https://github.com/zsh-users/zsh-autosuggestions/pull/753#issuecomment-1694146062).

I was able to produce errors with ZSH_AUTOSUGGEST_MANUAL_REBIND active and sourcing a file async-widget-setup.zsh after the first precmd with the plugin active. If manual rebind is not active or if the widgets are created before the first precmd, then zsh-autosuggestions wraps the widgets and for some reason we don't seem to get any fd conflicts.

The .zshrc:

ZSH_AUTOSUGGEST_MANUAL_REBIND=true
source zsh-autosuggestions.zsh

and async-widget-setup.zsh:

function async-widget-fork() {
    exec {fd}< <(echo foo)
    zle -M "opened: $fd, autosuggest fd: $_ZSH_AUTOSUGGEST_ASYNC_FD"
}

function async-widget-read() {
    zle -M "reading from $fd: $(cat <&$fd)"
}

zle -N async-widget-fork
zle -N async-widget-read

bindkey ^A async-widget-fork
bindkey ^B async-widget-read

Then run ZDOTDIR=$PWD zsh and:

  1. source async-widget-setup.zsh
  2. At the next prompt, type one character e.g. "a" to trigger an async request/response cycle. This leaves _ZSH_AUTOSUGGEST_ASYNC_FD set to the stale file descriptor number.
  3. Then press ^A to activate the fork. This will set the fd parameter to the same number as _ZSH_AUTOSUGGEST_ASYNC_FD.
  4. Then type another character e.g. "a" to trigger an async request. This will print a "No handler installed" error and close the file descriptor pointed to by both _ZSH_AUTOSUGGEST_ASYNC_FD and fd.
  5. Pressing ^B at this point will fail to read with a "bad file descriptor" error.