Comment la stack est-elle initialisée?

Lorsqu’un processus demande de la mémoire et qu’un système d’exploitation donne de nouvelles pages au processus, le kernel doit initialiser les pages (avec des zéros par exemple) afin d’éviter d’afficher des données potentiellement fiables utilisées par un autre processus. La même chose quand un processus démarre et reçoit de la mémoire, par exemple le segment de stack.

Lorsque j’exécute le code suivant sous Linux, le résultat est que la majorité de la mémoire allouée est bien 0, mais quelque chose de 3 à 4 Ko au bas de la stack (les derniers éléments du tableau, les adresses les plus hautes) contient des nombres aléatoires. .

#include  #include  using namespace std; int main() { int * a = (int*)alloca(sizeof(int)*2000000); for(int i = 0; i< 2000000; ++i) cout << a[i] << endl; return 0; } 
  1. Pourquoi n’est-il pas mis à zéro aussi?
  2. Pourrait-il être parce qu’il est réutilisé par le processus?
  3. Si oui, est-ce que ce serait le code d’initialisation qui avait utilisé ces 3-4 Ko de mémoire plus tôt?

Je suis presque certain que lorsque le système d’exploitation démarre votre processus, la stack ne contient que des zéros. Ce que vous observez est un autre phénomène, je pense. Vous semblez avoir compilé votre programme en C ++. C ++ fait beaucoup de code (constructeurs et autres) avant que votre main démarre. Donc, ce que vous voyez sont les valeurs restantes de votre propre exécution.

Si vous compiliez votre code en C (changez pour “stdio.h”, etc.), vous verriez probablement une “pollution” très réduite, voire pas du tout. En particulier si vous liez votre programme de manière statique à une version minimaliste d’une bibliothèque C.

Le système d’exploitation ne garantit pas une mémoire de zéro, juste que vous en êtes propriétaire. Il vous donnera probablement des pages de mémoire qui ont été utilisées auparavant (ou jamais utilisées auparavant, mais non nulles). Si une application stocke des données potentiellement sensibles, elle doit les mettre à zéro avant de libérer ().

Il n’est pas mis à zéro car cela entraînerait un travail inutile. Si vous allouez 20 mégaoctets pour stocker une texture ou quelques images de vidéo, pourquoi le système d’écriture va-t-il écrire des zéros dans toute cette mémoire pour que vous puissiez les remplacer par la suite.

En règle générale, les systèmes d’exploitation ne font rien de ce qu’ils n’ont pas à faire.

edit: pour développer un peu, lorsque vous “allouez” un bloc de mémoire, tout ce que le système d’exploitation fait, c’est ré-assigner des pages de mémoire (blocs de 4096 octets, généralement) à votre processus à partir d’un pool de pages non allouées. Vous pouvez également avoir de la mémoire partagée, auquel cas le système d’exploitation les «affecte» à plusieurs processus. Cela revient à.

Lorsque vous obtenez de la nouvelle mémoire dans votre processus via brk() , sbrk() ou mmap() il est garanti qu’il sera mis à zéro.

Mais la stack de processus est déjà allouée à votre processus. La fonction alloca() n’obtient pas de nouvel espace de stack, elle renvoie simplement le pointeur de stack en cours et déplace le pointeur vers la fin du nouveau bloc.

Ainsi, le bloc de mémoire renvoyé par alloca() a déjà été utilisé par votre processus. Même si vous n’avez pas de fonctions avant que votre alloca() en mode main, les bibliothèques C et le chargeur dynamic ont utilisé la stack.

Le sumt de la stack contient les définitions des variables d’environnement et, en dessous, les arguments de la ligne de commande et les tableaux environ et argv.

Sur un x86_64, un simple code de démarrage sous Linux pourrait ressembler à ceci:

 asm( " .text\n" " .align 16\n" " .globl _start\n" " .type _start,@function\n" "_start:\n" " xor %rbp, %rbp\n" // Clear the link register. " mov (%rsp), %rdi\n" // Get argc... " lea 8(%rsp), %rsi\n" // ... and argv ... " mov %rax, %rbx\n" // ... copy argc ... " inc %rbx\n" // ... argc + 1 ... " lea (%rsi, %rbx, 8), %rdx\n"// ... and compute environ. " andq $~15, %rsp\n" // Align the stack on a 16 byte boundry. " call _estart\n" // Let's go! " jmp .\n" // Never gets here. " .size _start, .-_start\n" ); 

Modifier:

J’ai complètement mal compris la question. Les éléments en haut de la stack dans votre code sont probablement le résultat du code de démarrage appelé avant que main () soit entré.

Il n’ya rien dans la documentation d’ alloca qui indique que la mémoire est initialisée, vous obtenez donc tout ce que vous n’avez pas trouvé.

Si vous voulez que la mémoire soit initialisée à zéro, vous pouvez faire l’évidence: allouer et initialiser manuellement avec memset . Ou vous pouvez utiliser calloc qui garantit que la mémoire est initialisée à zéro.