Il semble que la limite de mémoire de la pile ne soit pas allouée (de toute façon, elle ne le pourrait pas avec une pile illimitée). https://www.kernel.org/doc/Documentation/vm/overcommit-accounting dit :
La croissance de la pile du langage C effectue un mremap implicite. Si vous voulez des garanties absolues et que vous courez près du bord, vous DEVEZ mmapper votre pile pour la plus grande taille dont vous pensez avoir besoin. Pour une utilisation typique de la pile, cela n'a pas beaucoup d'importance, mais c'est un cas particulier si vous vous en souciez vraiment
Cependant, mmapper la pile serait l'objectif d'un compilateur (s'il a une option pour cela).
EDIT :Après quelques tests sur une machine Debian x84_64, j'ai constaté que la pile grandissait sans aucun appel système (selon strace
). Donc, cela signifie que le noyau le fait grandir automatiquement (c'est ce que signifie "implicite" ci-dessus), c'est-à-dire sans mmap
explicite /mremap
du processus.
Il était assez difficile de trouver des informations détaillées confirmant cela. Je recommande Understanding The Linux Virtual Memory Manager par Mel Gorman. Je suppose que la réponse se trouve dans la section 4.6.1 Gestion d'un défaut de page , à l'exception "Région non valide mais se trouve à côté d'une région extensible comme la pile" et l'action correspondante "Développer la région et allouer une page". Voir aussi D.5.2 Étendre la pile .
Autres références sur la gestion de la mémoire Linux (mais avec presque rien sur la pile) :
- FAQ sur la mémoire
- Ce que tout programmeur devrait savoir sur la mémoire par Ulrich Drepper
EDIT 2 :Cette implémentation a un inconvénient :dans les cas extrêmes, une collision pile-tas peut ne pas être détectée, même dans le cas où la pile serait plus grande que la limite ! La raison en est qu'une écriture dans une variable de la pile peut se retrouver dans la mémoire de tas allouée, auquel cas il n'y a pas de défaut de page et le noyau ne peut pas savoir que la pile devait être étendue. Voir mon exemple dans la discussion Silent stack-heap collision under GNU/Linux I started in the gcc-help list. Pour éviter cela, le compilateur doit ajouter du code à l'appel de la fonction ; cela peut être fait avec -fstack-check
pour GCC (voir la réponse de Ian Lance Taylor et la page de manuel de GCC pour plus de détails).
Noyau Linux 4.2
- mm/mmap.c#acct_stack_growth décide s'il y aura erreur de segmentation ou non. Il utilise
rlim[RLIMIT_STACK]
qui correspond au POSIXgerlimit(RLIMIT_STACK)
- arch/x86/mm/fault.c#do_page_fault est le gestionnaire d'interruption qui démarre une chaîne qui finit par appeler
acct_stack_growth
- arch/x86/entry/entry_64.S configure le gestionnaire de défauts de page. Vous devez en savoir un peu plus sur la pagination pour comprendre cette partie :comment fonctionne la pagination x86 ? | Débordement de pile
Programme de test minimal
Nous pouvons ensuite le tester avec un programme NASM 64 bits minimal :
global _start
_start:
sub rsp, 0x7FF000
mov [rsp], rax
mov rax, 60
mov rdi, 0
syscall
Assurez-vous de désactiver ASLR et de supprimer les variables d'environnement, car celles-ci iront sur la pile et prendront de la place :
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
env -i ./main.out
La limite est quelque part légèrement en dessous de mon ulimit -s
(8 Mo pour moi). Il semble que cela soit dû aux données supplémentaires spécifiées par System V initialement placées sur la pile en plus de l'environnement :Paramètres de ligne de commande Linux 64 dans Assembly | Débordement de pile
Si vous êtes sérieux à ce sujet, TODO créez une image initrd minimale qui commence à écrire à partir du haut de la pile et descend, puis exécutez-la avec QEMU + GDB. Mettez un dprintf
sur la boucle imprimant l'adresse de la pile, et un point d'arrêt à acct_stack_growth
. Ce sera glorieux.
Connexe :
- https://softwareengineering.stackexchange.com/questions/207386/how-are-the-size-of-the-stack-and-heap-limited-by-the-os
- D'où provient la mémoire de la pile allouée pour un processus Linux ? | Débordement de pile
- Qu'est-ce que la pile Linux ? | Débordement de pile
- Quelle est la profondeur de récursivité maximale en Python et comment l'augmenter ? sur débordement de pile
Par défaut, la taille maximale de la pile est configurée pour être de 8 Mo par processus,
mais il peut être modifié en utilisant ulimit
:
Affichage de la valeur par défaut en Ko :
$ ulimit -s
8192
Définir sur illimité :
ulimit -s unlimited
affectant le shell et les sous-shells actuels et leurs processus enfants.
(ulimit
est une commande intégrée du shell)
Vous pouvez afficher la plage d'adresses de pile réelle utilisée avec :
cat /proc/$PID/maps | grep -F '[stack]'
sous Linux.