Qu’est-ce qui cause un débordement de stack?

Vous pensez peut-être que c‘est une coïncidence si le sujet de ma question est similaire au nom du forum, mais je suis arrivé ici en recherchant le terme “débordement de stack”.

J’utilise le simulateur de réseau OPNET dans lequel je programme en utilisant C. Je pense que j’ai un problème avec les grandes tailles de tableau. Il semble que je suis frappé d’une sorte de limitation de l’allocation de mémoire. Cela peut avoir à voir avec OPNET, Windows, la mémoire de mon ordinateur portable ou très probablement le langage C. Le problème survient lorsque j’essaie d’utiliser des tableaux nesteds avec un nombre total d’éléments atteignant plusieurs milliers d’entiers. Je pense dépasser la limite globale d’allocation de mémoire et je me demande s’il est possible d’augmenter ce plafond. Voici la description exacte du problème:

J’ai essentiellement une table de routage. Appelons-le routing_tbl [n], ce qui signifie que je supporte 30 nœuds (routeurs). Maintenant, pour chaque noeud de cette table, je garde des informations. sur plusieurs (plusieurs) chemins disponibles, dans un tableau appelé chemins [p]. De nouveau, pour chaque chemin de ce tableau, je garde la liste des noeuds qui lui appartiennent dans un tableau appelé hops [h]. Donc, j’utilise au moins nph d’entiers en mémoire, mais ce tableau contient aussi d’autres informations. Dans la même fonction, j’utilise également un autre tableau nested qui consum près de 40 000 entiers. Dès que j’exécute ma simulation, elle cesse de se plaindre du débordement de stack. Cela fonctionne lorsque je réduis la taille totale de la table de routage. Selon vous, quelles sont les causes du problème et comment peut-on le résoudre? Très apprécié Ali

Cela peut aider si vous postez du code. Modifiez la question pour inclure la fonction problématique et l’erreur.

En attendant, voici une réponse très générique:

Les deux causes principales d’un débordement de stack sont 1) une fonction récursive ou 2) l’affectation d’un grand nombre de variables locales.

Récursion

si votre fonction s’appelle elle-même, comme ceci:

int recurse(int number) { return (recurse(number)); } 

Étant donné que les variables locales et les arguments de fonction sont stockés dans la stack, cela remplit la stack et provoque un débordement de la stack.

Grandes variables locales

Si vous essayez d’allouer un grand nombre de variables locales, vous pouvez déborder de la stack en une seule opération. Une fonction comme celle-ci peut causer le problème:

 void hugeStack (void) { unsigned long long reallyBig[100000000][1000000000]; ... } 

Il existe une réponse assez détaillée à cette question similaire .

D’une manière ou d’une autre, vous utilisez beaucoup de stack. Les causes possibles sont que vous créez la table de routage sur la stack, vous la passez sur la stack ou vous générez beaucoup d’appels (par exemple, en traitant de manière récursive le tout).

Dans les deux premiers cas, vous devez le créer sur le tas et lui faire passer un pointeur. Dans le troisième cas, vous devrez réécrire votre algorithme sous une forme itérative.

Des débordements de stack peuvent se produire en C lorsque le nombre d’appels récursifs incorporés est trop élevé. Peut-être appelez-vous une fonction trop souvent?

Cette erreur peut également être due à l’allocation de trop de mémoire dans les déclarations statiques. Vous pouvez passer aux allocations dynamics via malloc () pour résoudre ce type de problème.

Y a-t-il une raison pour laquelle vous ne pouvez pas utiliser le débogueur sur ce programme?

Cela dépend de l’endroit où vous avez déclaré la variable.

Une variable locale (c’est-à-dire qu’une déclaration déclarée sur la stack est limitée par la taille maximale de la trame). Il s’agit d’une limite du compilateur que vous utilisez (et peut généralement être ajustée avec les indicateurs du compilateur).

Un object alloué dynamicment (c’est-à-dire qui se trouve sur le tas) est limité par la quantité de mémoire disponible. Ceci est une propriété du système d’exploitation (et peut techniquement augmenter la mémoire physique si vous avez un système d’exploitation intelligent).

De nombreux systèmes d’exploitation développent dynamicment la stack à mesure que vous en utilisez davantage. Lorsque vous commencez à écrire sur une adresse mémoire qui se trouve juste au-delà de la stack, le système d’exploitation suppose que votre stack s’est encore agrandie un peu plus et lui atsortingbue une page supplémentaire (généralement 4096 Ko sur x86 – exactement 1024 pouces).

Le problème est que, sur le x86 (et quelques autres architectures), la stack croît vers le bas mais les masortingces C grandissent. Cela signifie que si vous accédez au début d’un grand tableau, vous aurez access à une mémoire située à plus d’une page du bord de la stack.

Si vous initialisez votre tableau à 0 à partir de la fin du tableau (c’est vrai, créez une boucle for pour le faire), les erreurs risquent de disparaître. S’ils le font, c’est bien le problème.

Vous pourrez peut-être trouver certaines fonctions de l’API du système d’exploitation pour forcer l’allocation de stack, ou des pragmas / indicateurs du compilateur. Je ne suis pas sûr de savoir comment cela peut être fait de manière portable, sauf bien sûr pour l’utilisation de malloc () et de free ()!

Il est peu probable que vous renconsortingez un dépassement de capacité avec le C compilé sans thread, sauf si vous faites quelque chose de particulièrement flagrant, comme une récursivité ou une fuite de mémoire cosmique. Cependant, votre simulateur a probablement un package de thread qui imposera des limites de taille de stack. Lorsque vous démarrez un nouveau thread, une quantité de mémoire est allouée à la stack pour ce thread. Probablement, il existe un paramètre que vous pouvez définir quelque part qui établit la taille de stack par défaut ou un moyen de développer la stack de manière dynamic. Par exemple, pthreads a une fonction pthread_attr_setstacksize () que vous appelez avant de démarrer un nouveau thread pour définir sa taille. Votre simulateur peut utiliser ou non des pthreads. Consultez la documentation de référence de votre simulateur.