странный сбой zsh segfault с определениями функций

Я нахожу это очень аккуратным, но я недостаточно вовлечен, чтобы понять, что происходит.

Кто-нибудь знает, почему такое поведение существует в zsh или что zsh пытается сделать, что вызывает segfault?

➜  ~  (echo "hi"(); echo "hi"; echo "hi")
[1]    65962 segmentation fault  ( echo "hi" () { ... }; echo "hi"; )

➜  ~  (ls(); ls; ls)
[1]    66073 segmentation fault  ( ls -G () { ... }; ls -G; )

Я помещаю его в подпроцесс, чтобы он распечатывал, что происходит; иначе, если вы, например, запустите ls(), затем заполните function> с помощью ls, затем снова запустите ls, он крашит терминал.

Это происходит только тогда, когда вы пытаетесь переопределить функции сами с собой, например, echo str1(); echo str2, но не ls(); echo str. Это работает не со всеми возможными входными данными, а только из-за разбора синтаксиса, например, хотя:

➜  ~  (^A(); ^A; ^A)
[1]    66154 segmentation fault  ( ^A () { ... }; ^A; )

это не работает по причинам синтаксиса, если вы запускаете его построчно:

➜  ~  ^A()
zsh: substitution failed

Как ни странно, такое поведение происходит:

➜  ~  a()
function> 7
➜  ~  a
a:cd:3: no such entry in dir stack
➜  ~  8()
function> b
➜  ~  8
cd:7: command not found: b
➜  ~  9()
function> 13
➜  ~  9
cd:6: command not found: 13

НО

➜  ~  9()
function> 5
➜  ~  (9)
[1]    66979 segmentation fault  ( cd -9; )

что привело бы к сбою терминала, если бы не в подпроцессе, а это означает, что вы можете определить однозначное число как функцию, которая ведет к двузначному числу, но не к однозначному! Это эквивалентно буквам (c(); a — это ошибка сегментации, c(); bh — «команда не найдена»). 71(); 81; 71; тоже не вызывает segfault.

Мне очень любопытно, что происходит под капотом! Это обеспечивает неприятный способ возиться с людьми, так как положить

echo $JAVA_HOME()
echo "hi" 

in .zshrc приведет к сбою терминала, даже если кто-то попытается использовать $JAVA_HOME только, скажем, в назначении переменной, это вызовет segfault, например,

➜  ~  ($JAVA_HOME)
[1]    66745 segmentation fault  ( $JAVA_HOME; )    
➜  ~  (X= $JAVA_HOME)
[1]    66737 segmentation fault  ( X= $JAVA_HOME; )

Возможно, это также требует исправления в будущем, так как я могу представить, что это может быть использовано в грубых целях. Это известная проблема?

Это не работает в bash из-за того, как bash анализирует определения функций.


person Lane Erickson    schedule 10.11.2015    source источник
comment
(echo hi(); echo hi; echo hi) может быть ошибкой, но насчет однозначных и двузначных чисел: вероятно, все ваши однозначные числа имеют псевдоним cd +$digit (или cd -$digit). Проверьте alias 1, alias 2, ..., alias 9, и вы поймете, что это уловка вашей конфигурации (в Prezto это directory). Тем не менее мне неясно, почему это может привести к segfault; наверное тоже баг. Сообщите об этом по адресу [email protected].   -  person 4ae1e1    schedule 11.11.2015
comment
Вам действительно следует сообщить об ошибке по адресу [email protected].   -  person Francisco    schedule 11.11.2015
comment
Обратите внимание, что segfault является ошибкой. Легко и просто. Оболочка должна выводить ошибку, если синтаксис неправильный или когда пользователь делает забавные вещи, а не сбой.   -  person Francisco    schedule 11.11.2015


Ответы (1)


➜  ~  (echo "hi"(); echo "hi"; echo "hi")
[1]    65962 segmentation fault  ( echo "hi" () { ... }; echo "hi"; )

➜  ~  (ls(); ls; ls)
[1]    66073 segmentation fault  ( ls -G () { ... }; ls -G; )

Для моего zsh это печатает

echo:1: maximum nested function level reached

и

ls:2: maximum nested function level reached

соответственно.



Итак, давайте посмотрим, что они делают. Что

echo "hi"(); echo "hi"; echo "hi"

на самом деле делают это:

# Define functions "echo" and "hi" that will both execute the following code when called
function echo hi() {
    # These are what the function actually contains.  This means that inside of "echo," will be another "echo" that is calling the first echo with a (discarded) $1 of "hi."  Recursion!
    echo hi
}
# We haven't tripped up yet: we have yet to actually *call* this code.
echo "hi"
# And now we have.  Echo calls echo which calls echo, recursing too many times for zsh to handle.  This is known as "Stack Overflow," which is incidentally also the name of this site.

Почти то же самое происходит с "ls" и "^A".



➜  ~  a()
function> 7
➜  ~  a
a:cd:3: no such entry in dir stack
➜  ~  8()
function> b
➜  ~  8
cd:7: command not found: b
➜  ~  9()
function> 13
➜  ~  9
cd:6: command not found: 13

Я не знаю, что происходит с определением a(), но все остальные совершенно нормальны. Вы, например, определяете функцию «9», которая будет вызывать команду «13», а zsh жалуется, что нет команды с именем «13», поэтому ему нечего делать.

➜  ~  9()
function> 5
➜  ~  (9)
[1]    66979 segmentation fault  ( cd -9; )

Я честно не знаю, что происходит с этим. Вы используете действительно старую версию zsh или что-то в этом роде? В качестве примечания для всех, кто читает эту ветку, когда я пытаюсь дать определение этому, требуется много времени, чтобы вернуться к подсказке - этого не произошло ни с одним из других, кто-нибудь знает причину?

echo $JAVA_HOME()
echo "hi"

Это почти то же самое, что и раньше. Это определит функцию, вызываемую либо "echo", либо значением $JAVA_HOME, если она установлена, которая вызовет "echo", которая вызовет "echo", которая вызовет "echo", и у нас снова будет переполнение стека.




Надеюсь, что ответил на ваш вопрос, и если у вас есть еще, не стесняйтесь спрашивать!

person Moonchild    schedule 15.02.2016