Bonjour,
Comment marche cette commande qui fait planter le pinguoin: <<:(){ :|:&};:>>
(enlever le << et le >>).
Je l'ai testée sous fedora, le système se fige...
sincèrement
Bonjour,
Comment marche cette commande qui fait planter le pinguoin: <<:(){ :|:&};:>>
(enlever le << et le >>).
Je l'ai testée sous fedora, le système se fige...
sincèrement
Vous seriez nantais, que je n'en serai pas surpris
Ce code :joue sur le fait que le shell (bash) accepte : comme nom valide pour une fonction. on peut le ré-écrire, de façon plus lisible, ainsi :
Code : Sélectionner tout - Visualiser dans une fenêtre à part :(){ :|:&};:On définit ainsi une fonction récursive, dont la définition fait une première fois appel à elle même, pipée sur une seconde invocation, détachée en tâche de fond (donc dans un nouveau processus).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 ma_fonction () { ma_fonction | ma_fonction& } ma_fonction
On lance ensuite cette fonction tueuse ...
Le système se fige alors rapidement à cause de la multiplication des forks qui en résulte ...
Ca fait planter tout système d'exploitation, pas seulement Linux.
C'est une boucle infinie...
Ca fait planter tout système d'exploitation, pas seulement Linux.
C'est une boucle infinie...
merci pour ce rappel, j'oubliais que linux c'est QUE le noyau. (sourire)
Une simple fonction réccursive qui se rappel à l'infini ne provoquerait pas le même effet ?
Bash attend bien que la fonction ait fini de s'exécuté avant de piper le contenu non ? Et comme le premier appel ne rend pas la main, il n'y a aucun contenu pipé, donc le deuxième appel (celui juste après le pipe) n'est jamais exécuté.
Enfin voilà, des gens sont-ils capable d'expliquer précisément toutes les étapes avant le freez ?
Plus ou moins ... dans le cas présent, l'effet de la récursion est amplifié par la multiplication des processus liée au fork.Envoyé par Celelibi
Je ne le crois pas ... il suffit, pour s'en convaincre, de lancer un programme dont l'exécution est très longue et qui affiche des résultats de temps en temps. Si on le pipe sur less (ou more, pour les *vrais* unices), les données s'afficheront au fur et à mesure et less marquera une fin de page chaque fois qu'il aura assez de données. Il n'attendra pas la fin de l'exécution du programme.Envoyé par Celelibi
Il y a donc bien exécution simultanée de ce qui est avant le pipe et de ce qui est après et en attends les données. La preuve par l'exemple :
Code : Sélectionner tout - Visualiser dans une fenêtre à part { for i in $( seq 1 120) ; do echo $i ; sleep 1; done } | lessComme on vient de le voir, les deux appels sont exécutés, générant une cascade d'autres appels (un appel en provoque deux, qui en provoquent deux chacun, etc.)Envoyé par Celelibi
A la dixième génération, on a déja 512 + 256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 1023 appels simultanés, et ça double encore ...)
A un moment ou à un autre, le système ne peut plus faire de nouveaux forks (limite du nombre de processus atteinte). Il n'est alors plus possible de lancer la moindre commande ...Envoyé par Celelibi
A moins d'avoir, actif au préalable, un watchdog qui va flinguer ce qui pose problème, c'est le blocage.
La machine n'est plus récupérable, puis qu'il devient impossible de s'y connecter (plus de fork pour lancer de nouveaux shells) et les connexions déjà établies sont inutilisables (plus de fork pour lancer les commandes).
Je me demande (je n'ai pas voulu tester, j'ai besoin de ma machine) s'il n'est pas possible d'éviter le phénomène en donnant de bonnes valeurs à ulimit (-u, -v et -p par exemple).
tant qu'on est dans ce genre de question :
la fonction recursive :Envoyé par Celelibi
Plus ou moins ... dans le cas présent, l'effet de la récursion est amplifié par la multiplication des processus liée au fork.
va a chaque appel consommer un soupson de memoire,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 ma_fonction () { ma_fonction } ma_fonction
mais quand il n'y en aura plus, ne vas telle tout simplement pas planter, mourir et liberer la memoire utilisé ?
(j'ai pas trop envie de tester, la derniere fois j'ai du reinstaller le systeme avec des betises pareilles)
2Eurocents, comme l'a un peu dit xlurp, lorsque la limite de processus est atteinte, l'appel à la fonction devrait échouer et la fonction appellante devrait rendre la main et donc tout ça devrait "dérécursionner".
Si ce que j'ai dit s'avère vrai, il suffit de rajouter une boucle infinie
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 ma_fonction () { while [ 1 ]; do ma_fonction | ma_fonction &; done; } ma_fonctionNe pas tenter à la maison ! ^^
Sous linux, ca freeze lamentablement car il n'y a pas de controle sur le nombre de processus : on rempli allegrement la table des process en mémoire, puis éventuellement on swap des process pour faire de la place et accueillir les (toujours) nouveau processus qui sont créés. Manque de pot, dans le tas, il y a des processus sytèmes "utiles" (scheduler, swapper), etc...
Là où ca devient dramatique, c'est lorsqu'un processus sytème "important" veut (doit) reprendre la main (un de ceux cités précédemment) : il est forcément sur le swap, puisqu'on a tout rempli avec la bombe fork : problème, il n'y a plus de place dans la table des processus pour permettre de dé-swapper le process en question... On attend donc qu'il y en ai un qui rende la main... Et comme ça n'arrive jamais, on freeze...
Par contre, sur un FreeBSD, il n'y a pas ce genre de problème, car le système conserve par devers tout une petite place dans la table des processus dédiée aux processus sytèmes : ceux-ci pourront donc toujours swapper... Donc sur un FreeBSD (j'ai testé pour vous), ca ne freeze pas
![]()
Avec cette commande on peut limiter le nombre de processus pour un utilisateur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part man setrlimit
Non, pas du tout car comme l'ordonnanceur n'est pas surchargé, le système arrivera toujours à donner la main aux autres processus ==> tu pourras donc tuer le processus gênant sans aucune difficulté.Envoyé par Celelibi
Et quand il n'y aura plus assez de mémoire pour les appels récursifs, tu auras droit à une belle erreur de segmentation qui interrompra ton processus sans cause le moindre dégât au niveau du système.![]()
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 $ vi toto.c toto() { toto(); } main() { toto(); } :wq $ make toto $ ./toto segmentation fault![]()
Partager