Advertencia: ejecutar este comando en la mayoría de los shells dará como resultado un sistema dañado que necesitará un apagado forzado para solucionarlo
Entiendo la función recursiva :(){ :|: & };:
y lo que hace. Pero no sé dónde está la llamada del sistema fork. No estoy seguro, pero sospecho que en la tubería |
.
linux
shell
system-calls
mavillan
fuente
fuente
Respuestas:
Como resultado de la canalización
x | y
, se crea una subshell para contener la canalización como parte del grupo de procesos en primer plano. Esto continúa creando subcapas (víafork()
) indefinidamente, creando así una bomba tenedor.La bifurcación en realidad no ocurre hasta que se ejecuta el código, sin embargo, que es la invocación final de
:
su código.Para desmontar cómo funciona la bomba tenedor:
:()
- define una nueva función llamada:
{ :|: & }
- una definición de función que canaliza recursivamente la función de llamada en otra instancia de la función de llamada en segundo plano:
- llama a la función de bomba tenedorEsto tiende a no consumir demasiado memoria, pero absorberá los PID y consumirá ciclos de CPU.
fuente
x | y
, ¿por qué hay un sub-shell creado? A mi entender, cuando bash ve unpipe
, ejecuta unapipe()
llamada al sistema, que devuelve dosfds
. Ahora, command_left se editaexec
y la salida se alimenta a command_right como entrada. Ahora, command_right esexec
ed. Entonces, ¿por qué esBASHPID
diferente cada vez?x
yy
hay 2 comandos separados ejecutándose en 2 procesos separados, por lo que tiene 2 subcapas separadas. Si sex
ejecuta en el mismo proceso que el shell, eso significa quex
debe estar integrado.El último bit del código,
;:
está ejecutando la función:(){ ... }
. Aquí es donde está ocurriendo la bifurcación.El punto y coma termina el primer comando, y estamos comenzando otro, es decir, invocando la función
:
. La definición de esta función incluye una llamada a sí mismo (:
) y la salida de esta llamada se canaliza a una versión en segundo plano:
. Esto apuntala el proceso indefinidamente.Cada vez que usted está llamando a la función
:()
que está llamando la función Cfork()
. Finalmente, esto agotará todas las ID de proceso (PID) en el sistema.Ejemplo
Puede intercambiarlo
|:&
con otra cosa para tener una idea de lo que está sucediendo.Configurar un observador
En una ventana de terminal, haga esto:
Configurar la bomba de horquilla "fusible retrasado"
En otra ventana, ejecutaremos una versión ligeramente modificada de la bomba tenedor. Esta versión intentará estrangularse para que podamos estudiar lo que está haciendo. Nuestra versión dormirá durante 61 segundos antes de llamar a la función
:()
.También haremos un fondo de la llamada inicial, después de que se invoque. Ctrl+ z, luego escriba
bg
.Ahora, si ejecutamos el
jobs
comando en la ventana inicial, veremos esto:Después de un par de minutos:
Registrarse con el observador
Mientras tanto, en la otra ventana donde estamos corriendo
watch
:Jerarquía de procesos
Y a
ps -auxf
muestra esta jerarquía de procesos:Tiempo de limpieza
A
killall bash
detendrá las cosas antes de que se salgan de control. Hacer la limpieza de esta manera puede ser un poco pesado, una forma más amable y gentil que no desgarrará cadabash
caparazón sería hacer lo siguiente:Determine en qué pseudo terminal se ejecutará la bomba tenedor
Mata el pseudo terminal
Entonces, ¿qué está pasando?
Bueno, cada invocación de
bash
ysleep
es una llamada a la función Cfork()
desde elbash
shell desde donde se ejecutó el comando.fuente
bash
podría estar ejecutándose en terminales separadas. Mejor sería usarlopkill -t pts/2
.