mirror of
https://github.com/junegunn/fzf.git
synced 2026-06-25 02:13:52 +08:00
Skip FZF_CURRENT_ITEM export for items larger than 64 KB
A huge item can overflow ARG_MAX and break exec with E2BIG, failing preview and other child commands. (#4806)
This commit is contained in:
@@ -12,6 +12,7 @@ CHANGELOG
|
||||
--bind 'result:transform-header(echo result: $FZF_MATCH_COUNT),result-final:transform-footer(echo final: $FZF_MATCH_COUNT)'
|
||||
```
|
||||
- Bound `alt-left` to `backward-word` and `alt-right` to `forward-word` by default (#4833)
|
||||
- Skip `$FZF_CURRENT_ITEM` export when the item is larger than 64 KB; a huge item can overflow `ARG_MAX` and break preview and other child commands with `E2BIG` (#4806)
|
||||
|
||||
0.73.1
|
||||
------
|
||||
|
||||
@@ -1534,6 +1534,9 @@ fzf exports the following environment variables to its child processes.
|
||||
.PP
|
||||
.B FZF_CURRENT_ITEM
|
||||
is omitted when the item contains a NUL byte, because exec(2) cannot pass it.
|
||||
It is also omitted when the item is larger than 64 KB, so that a huge item
|
||||
cannot overflow the environment size limit and break preview and other child
|
||||
commands.
|
||||
|
||||
.SH EXTENDED SEARCH MODE
|
||||
|
||||
|
||||
+8
-2
@@ -68,6 +68,10 @@ const maxFocusEvents = 10000
|
||||
// After this duration, users can press CTRL-C to terminate the command.
|
||||
const blockDuration = 1 * time.Second
|
||||
|
||||
// Skip exporting FZF_CURRENT_ITEM when the item is larger than this, so a huge
|
||||
// item cannot overflow ARG_MAX and break exec for preview and other commands.
|
||||
const maxCurrentItemEnvSize = 64 * 1024
|
||||
|
||||
func init() {
|
||||
placeholder = regexp.MustCompile(`\\?(?:{[+*sfr]*[0-9,-.]*}|{q(?::s?[0-9,-.]+)?}|{fzf:(?:query|action|prompt)}|{[+*]?f?nf?})`)
|
||||
whiteSuffix = regexp.MustCompile(`\s*$`)
|
||||
@@ -1444,8 +1448,10 @@ func (t *Terminal) environImpl(forPreview bool) []string {
|
||||
env = append(env, fmt.Sprintf("FZF_COLUMNS=%d", t.areaColumns))
|
||||
env = append(env, fmt.Sprintf("FZF_POS=%d", min(t.merger.Length(), t.cy+1)))
|
||||
if item := t.currentItem(); item != nil {
|
||||
// Skip if the value contains a NUL byte; exec(2) would reject the env.
|
||||
if s := item.AsString(t.ansi); !strings.ContainsRune(s, 0) {
|
||||
// Skip if the value contains a NUL byte (exec(2) would reject the env)
|
||||
// or is too large (a huge item can overflow ARG_MAX and break exec
|
||||
// entirely for preview and other child commands).
|
||||
if s := item.AsString(t.ansi); !strings.ContainsRune(s, 0) && len(s) <= maxCurrentItemEnvSize {
|
||||
env = append(env, "FZF_CURRENT_ITEM="+s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2346,6 +2346,26 @@ class TestCore < TestInteractive
|
||||
end
|
||||
end
|
||||
|
||||
def test_env_current_item_size_limit
|
||||
preview = %[(echo START; env | grep '^FZF_CURRENT_ITEM='; echo END) > #{tempname}]
|
||||
# Large item (> 64 KB) is omitted so it cannot overflow ARG_MAX and break exec
|
||||
tmux.send_keys %(head -c 70000 /dev/zero | tr '\\0' a | #{FZF} --preview-window 0 --preview "#{preview}"), :Enter
|
||||
wait do
|
||||
content = File.exist?(tempname) ? File.read(tempname) : ''
|
||||
assert_includes content, 'END'
|
||||
refute_includes content, 'FZF_CURRENT_ITEM='
|
||||
end
|
||||
tmux.send_keys :Enter
|
||||
FileUtils.rm_f(tempname)
|
||||
# Smaller item is exported as usual
|
||||
tmux.send_keys %(head -c 1000 /dev/zero | tr '\\0' a | #{FZF} --preview-window 0 --preview "#{preview}"), :Enter
|
||||
wait do
|
||||
content = File.exist?(tempname) ? File.read(tempname) : ''
|
||||
assert_includes content, 'END'
|
||||
assert_includes content, 'FZF_CURRENT_ITEM=' + ('a' * 1000)
|
||||
end
|
||||
end
|
||||
|
||||
def test_abort_action_chain
|
||||
tmux.send_keys %(seq 100 | #{FZF} --bind 'load:accept+up+up' > #{tempname}), :Enter
|
||||
wait do
|
||||
|
||||
Reference in New Issue
Block a user