Dialogue imaginaire:
|
Au fait!
fa$ ps -p 11025 -f UID PID PPID C STIME TTY TIME CMD francois 11025 11024 0 16:33 pts/2 00:00:00 [arturo] fa$ |
Donc? Ce processus (sur un système Ubuntu) est-il un zombie ou non ? On ne parle pas ici de l'utilisateur mais bien du processus. Il arrive donc qu'en présence d'une trace comme celle montrée ci-dessus, Robert s'exclame : "Un zombie !"
Zombie
Un processus zombie est un processus qui a terminé son exécution via exit() ou des moyens plus violents, mais dont le père n'a pas encore ouvert le faire-part de décès: en bref, le père n'a pas invoqué l'appel wait(). Il y d'autres moyens à la disposition du processus père.Usine à zombie
Voici un petit programme qui crée entre 1 et 16 zombies, puis attend 3 minutes avant de disparaître. Les zombies disparaîtront aussi, parce que leur père ayant cessé son existence en ignorant la leur, les zombies orphelins, se retrouveront rattachés au processus 1 (init) qui les fera passer de zombie à inexistant.
fa$ cat zombie_factory.c #include <stdlib.h> #include <unistd.h> int main(int argc, char** argv) { int pid; unsigned long nb = 1; if (argc >= 2) { nb = strtol(argv[1], NULL, 10); if (nb > 16) nb = 16; } for(; nb > 0; nb--) { pid = fork(); if (pid == -1) { perror("Cannot fork"); exit(1); } if (pid == 0) exit(0); } sleep(180); return 0; } |
Robert aurait raison?
Si on lance ce processus et que l'on examine le résultat d'un ps:
fa$ ./zombie_factory 4 & [2] 11284 fa$ ps -f UID PID PPID C STIME TTY TIME CMD francois 11284 2132 0 11:39 pts/2 00:00:00 ./zombie_factory 4 francois 11285 11284 0 11:39 pts/2 00:00:00 [zombie_factory] <defunct> francois 11286 11284 0 11:39 pts/2 00:00:00 [zombie_factory] <defunct> francois 11287 11284 0 11:39 pts/2 00:00:00 [zombie_factory] <defunct> francois 11288 11284 0 11:39 pts/2 00:00:00 [zombie_factory] <defunct> francois 11289 2132 0 11:39 pts/2 00:00:00 ps -f fa$ |
Ah, oui les processus décédés ont bien leur nom de commande entre crochets. mais ils sont aussi marqués comme <defunct>. Notre premier processus [arturo] n'avait pas la mention <defunct>. Erreur ou oubli de la morgue?
Zombie or not Zombie?
Si on ajoute l'indicateur -l à la commande ps, on obtient alors aussi l'état (status) du processus, en deuxième colonne. L'état de notre processus est "S" : dormant (sleeping).
fa$ ps -p 11025 -fl F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 0 S francois 11025 11024 0 80 0 - 501 hrtime 11:49 pts/2 00:00:00 [arturo] fa$ |
L'état d'un processus zombie est normalement "Z". Vérifions:
fa$ ./zombie_factory & [2] 11321 F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 1 Z francois 11322 11321 0 80 0 - 0 exit 12:02 pts/2 00:00:00 [zombie_factory] <defunct> fa$ |
Donc...
Robert a tort
Notre processus [arturo] n'est pas en état "Z" mais en état "S". Il ne s'agit donc pas d'un zombie. Désolé Robert. Mais pourquoi son nom apparaît-il entre crochets? RTFM !Extrait de la page manuel ps
... Modifications to the arguments may be shown.
... Sometimes the process args will be unavailable; when this happens, ps will instead print the executable name in brackets
Entrée en scène d'Arturo
Donc, si on modifie les arguments, ou si les arguments sont inaccessibles... les modifications apportées seront visibles, ou le nom du processus sera affiché entre crochet.Commençons par essayer de rendre les arguments inaccessibles... Ben, il n'y a qu'à pas en passer lors de l'exec. Ce n'est après tout qu'une convention de mettre le nom de la commande en argv[0] et non une obligation. Mettons un peu de désordre dans les conventions.
J´ai fantaisie de mett´ dans notre vie Un p´tit grain de fantaisie! Youpi, Youpi´ (B. Lapointe)
fa$ cat arturo.c #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <signal.h> int main(int argc, char** argv) { int pid; int res; if (argc >= 1) { pid = fork(); if (pid == -1) { perror("Cannot fork"); exit(1); } if (pid == 0) { res = execve(argv[0], NULL, NULL); perror("Cannot exec!"); } sleep(1); system("ps -fl"); kill(pid, SIGKILL); return 0; } sleep(180); return 0; } |
Le processus ci-dessus va créer un fils qui va faire exec du même programme, mais sans recevoir aucun argument.
fa$ ./arturo F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 0 S francois 11473 2132 0 80 0 - 501 wait 16:39 pts/2 00:00:00 ./arturo 0 S francois 11474 11473 0 80 0 - 501 hrtime 16:39 pts/2 00:00:00 [arturo] fa$ |
Donc, quand les arguments ne sont pas disponibles (dans la pile utilisateur) notre processus apparaît effectivement avec son nom "crocheté", mais n'est en aucun cas un zombie.
Note: Le programme ci-dessus ne fonctionne pas sur Solaris (sur la version de Solaris sur laquelle j'ai essayée) : l'appel exec renvoie EFAULT. Il faut absolument passer comme argv un tableau contenant un pointeur NULL. Ce n'est apparemment pas le cas pour le troisième paramètre de exec: envp...
Comprend qui peut ou comprend qui veut (B. Lapointe)
Le Jardinier sauvage
Puisque les arguments sont dans la pile utilisateur, que se passe-t-il si volontairement ou par mégarde, on vient piétiner ces plate-bandes?Essayons!
fa$ cat arturo.c #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <signal.h> int main(int argc, char** argv) { int pid; int res; if (argc >= 1) { pid = fork(); if (pid == -1) { perror("Cannot fork"); exit(1); } if (pid == 0) { res = execve(argv[0], NULL, NULL); perror("Cannot exec!"); } for(; lg >= 0; lg--) argv[0][lg] = '\0'; argv[0] = NULL; sleep(1); system("ps -fl"); kill(pid, SIGKILL); return 0; } sleep(180); return 0; } |
Dans notre programme précédent, dans le cas du père, on efface avec des caractères nuls, la moitié de la chaîne argv[0]. Et surcroît de sauvagerie, on met le pointeur argv[0] à NULL.
Action.
fa$ ./arturo F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 0 S francois 11485 2132 0 80 0 - 501 wait 16:56 pts/2 00:00:00 uro 0 S francois 11486 11485 0 80 0 - 501 hrtime 16:56 pts/2 00:00:00 [arturo] fa$ |
Euh? Le père voit son nom de commande tronqué. C'est normal. on vient de labourer joyeusement la chaîne de caractères. Mais il semblerait que les caractères nuls insérés soient remplacés par des espaces.
En fait, cela semble dépendre des versions de la commande ps.
- La version procps-ng version 3.3.3 avec laquelle j'ai effectuée ces essais montre le nom tronqué.
- La version procps version 3.2.8 donne le résultat ci-dessous. Hop, invoquons Harry Houdini, un processus anonyme!
- Bonsoir, je m'appelle " "
- Bonsoir " "
- J'ai habitude de jardiner sauvagement les données dans ma pile.
fa$ ./arturo F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 0 S francois 17178 3131 0 80 0 - 459 wait 17:03 pts/0 00:00:00 <=== Là il n'y a rien! 0 S francois 17179 17178 0 80 0 - 459 hrtime 17:03 pts/0 00:00:00 [arturo] fa$ |
Sur AIX le processus anonyme apparaît avec le nom passé en premier argument de exec.
Faut-il une conclusion?
To zombie or not to zombie, là n'est plus la question.Pour se débarrasser des zombies, une requête sue le web vous donnera des tonnes de réponses. Des bonnes, des mauvaises, des étranges. Soyez "écolos" faîtes le tri.
Générique
Par ordre d'entrée en scène:- Robert Neville
- Arturo Brachetti
- Jean-Batpiste de La Quintinie
- Harry Houdini