Почему sh, zsh и bash возвращают ноль при выполнении файла нулевого байта? - PullRequest
2 голосов
/ 21 июня 2019

Почему вы можете выполнить пустой файл в bash, zsh или sh, и он выйдет из кода 0, когда системный вызов execve с пустым файлом выйдет из ENOEXEC?

touch zero
chmod +x zero
./zero
echo $?
0

execve выход -1 с ENOEXEC Exec format error, так что это не поведение операционной системы.

strace -f ./zero
execve("./zero", ["./zero"], [/* 53 vars */]) = -1 ENOEXEC (Exec format error)
write(2, "strace: exec: Exec format error\n", 32strace: exec: Exec format error
) = 32
exit_group(1)                           = ?
+++ exited with 1 +++

sh также вызывает execve и получает -ENOEXEC, но продолжает читать 80 байт файла и завершать работу с нуля.

strace -f sh -c "./zero"
...
execve("./zero", ["./zero"], [/* 52 vars */]) = -1 ENOEXEC (Exec format error)
open("./zero", O_RDONLY)                = 3
read(3, "", 80)                         = 0
close(3)                                = 0
exit_group(0)        

1 Ответ

2 голосов
/ 21 июня 2019

Если execve(2) возвращает ошибку и устанавливает errno на ENOEXEC, все оболочки будут пытаться запустить исполняемый файл в виде сценария оболочки, т.е.они будут выполнять оболочку с файлом, указанным в качестве аргумента.Пустой сценарий будет иметь нулевое состояние выхода (= успех) [1].

Какая оболочка будет запускаться, зависит: bash, ksh93 и yash запустят сценарий самостоятельно;csh, dash, zsh или mksh всегда будут запускать его, используя /bin/sh.

Это поведение очень старое и предшествует функции she-bang и стандартизированным форматам исполняемых файлов, иэто также требуется стандартом - прочитайте раздел 2. Поиск и выполнение команд из стандарта.

execve выход -1 с ENOEXEC Exec format error так что это не поведение операционной системы.

Это, однако, стандартное необходимое поведение для оболочек библиотеки execvp() и execlp():

В случае, если другие члены семейства функций exec потерпят неудачу и установят errno в ENOEXEC, функции execlp() и execvp() должны выполнить интерпретатор команд, а среда исполняемой команды должнабыть так, как если бы процесс вызвал утилиту sh, используя execl() следующим образом:

execl(<shell path>, arg0, file, arg1, ..., (char *)0);`

[1] В старой системе /bin/true был файл, состоящий только из уведомления об авторских правах, сообщая, что это"неопубликованный проприетарный исходный код AT& Т».

...