alloca()
alloue de la mémoire sur la pile plutôt que sur le tas, comme dans le cas de malloc()
. Donc, quand je reviens de la routine, la mémoire est libérée. Donc, en fait, cela résout mon problème de libération de mémoire allouée dynamiquement. La libération de la mémoire allouée malloc()
est un casse-tête majeur et si elle est manquée, elle entraîne toutes sortes de problèmes de mémoire.
Pourquoi est-il alloca()
déconseillé malgré les fonctionnalités ci-dessus?
free
(ce qui est évidemment un avantage) , l'impossibilité de l'inline (les allocations de tas sont évidemment beaucoup plus lourdes) et etc. La seule raison à éviteralloca
est pour les grandes tailles. Autrement dit, gaspiller des tonnes de mémoire de pile n'est pas une bonne idée, et vous avez également la possibilité d'un débordement de pile. Si tel est le cas - envisagez d'utilisermalloca
/freea
alloca
est que la pile ne peut pas être fragmentée comme le tas. Cela pourrait s'avérer utile pour les applications de style run-forever en temps réel, ou même pour les applications critiques pour la sécurité, car la WCRU peut ensuite être analysée statiquement sans recourir à des pools de mémoire personnalisés avec leur propre ensemble de problèmes (pas de localité temporelle, ressource sous-optimale utilisation).Réponses:
La réponse est juste là dans la
man
page (au moins sous Linux ):Ce qui ne veut pas dire qu'il ne devrait jamais être utilisé. L'un des projets OSS sur lequel je travaille l'utilise largement, et tant que vous n'en abusez pas (avec
alloca
des valeurs énormes), ça va. Une fois que vous avez dépassé la marque "quelques centaines d'octets", il est temps d'utiliser à la place desmalloc
amis. Vous pouvez toujours obtenir des échecs d'allocation, mais au moins vous aurez une indication de l'échec au lieu de simplement faire exploser la pile.la source
alloca()
n'ont pas la même peur des tableaux locaux ou de la récursivité (en fait, beaucoup de gens qui crierontalloca()
feront l'éloge de la récursivité parce qu'elle "a l'air élégante") . Je suis d'accord avec les conseils de Shaun ("alloca () est très bien pour les petites allocations") mais je ne suis pas d'accord avec la mentalité selon laquelle les cadres alloca () sont uniquement mauvais parmi les 3 - ils sont tout aussi dangereux!L'un des bugs les plus mémorables que j'ai eu a été de faire avec une fonction en ligne utilisée
alloca
. Il s'est manifesté comme un débordement de pile (car il alloue sur la pile) à des points aléatoires de l'exécution du programme.Dans le fichier d'en-tête:
Dans le fichier d'implémentation:
Donc, ce qui s'est passé était la
DoSomething
fonction en ligne du compilateur et toutes les allocations de pile se passaient à l'intérieur de laProcess()
fonction et faisaient ainsi exploser la pile. Pour ma défense (et ce n'est pas moi qui ai trouvé le problème; j'ai dû aller crier à l'un des développeurs seniors quand je n'ai pas pu le réparer), ce n'était pas simplealloca
, c'était une conversion de chaîne ATL macros.La leçon est donc - ne pas utiliser
alloca
dans des fonctions qui, selon vous, pourraient être intégrées.la source
Vieille question mais personne n'a mentionné qu'elle devrait être remplacée par des tableaux de longueur variable.
au lieu de
C'est dans la norme C99 et existait comme extension de compilateur dans de nombreux compilateurs.
la source
alloca () est très utile si vous ne pouvez pas utiliser une variable locale standard car sa taille doit être déterminée lors de l'exécution et vous pouvez absolument garantir que le pointeur que vous obtenez de alloca () ne sera JAMAIS utilisé après le retour de cette fonction .
Vous pouvez être assez en sécurité si vous
Le vrai danger vient de la possibilité que quelqu'un d'autre viole ces conditions un peu plus tard. Dans cet esprit, il est idéal pour passer des tampons aux fonctions qui mettent en forme du texte dedans :)
la source
alloca()
alloue de la mémoire qui dure jusqu'à la fin de la fonction. Cela signifie qu'il ne semble pas y avoir de traduction simple et pratique en VLA def() { char *p; if (c) { /* compute x */ p = alloca(x); } else { p = 0; } /* use p */ }
. Si vous pensez qu'il est possible de traduire automatiquement les utilisations dealloca
en utilisations de VLA mais que vous avez besoin de plus d'un commentaire pour décrire comment, je peux en faire une question.Comme indiqué dans cette publication de groupe de discussion , il existe plusieurs raisons pour lesquelles l'utilisation
alloca
peut être considérée comme difficile et dangereuse:alloca
.alloca
différemment le comportement souhaité , de sorte que la portabilité n'est pas garantie même entre les compilateurs qui le prennent en charge.la source
alloca()
nécessite des registres séparés pour contenir le pointeur de pile et le pointeur de trame. Sur les processeurs x86> = 386, le pointeur de pileESP
peut être utilisé pour les deux, libérantEBP
- à moins qu'il nealloca()
soit utilisé.f(42, alloca(10), 43);
pourrait se bloquer en raison de la possibilité que le pointeur de pile soit ajustéalloca()
après qu'au moins un des arguments ait été poussé dessus.Un problème est qu'il n'est pas standard, bien qu'il soit largement pris en charge. Toutes choses étant égales par ailleurs, j'utiliserais toujours une fonction standard plutôt qu'une extension de compilateur commune.
la source
Je ne perçois pas un tel consensus. Beaucoup de pros solides; quelques inconvénients:
while
oufor
) ou dans plusieurs étendues, la mémoire s'accumule par itération / étendue et n'est libérée que lorsque la fonction se termine: cela contraste avec les variables normales définies dans l'étendue d'une structure de contrôle (par ex.for {int i = 0; i < 2; ++i) { X }
accumulerait laalloca
mémoire demandée en X, mais la mémoire d'un tableau de taille fixe serait recyclée par itération).inline
fonctionner cet appelalloca
, mais si vous les forcez, celaalloca
se produira dans le contexte des appelants (c'est-à-dire que la pile ne sera pas libérée avant le retour de l'appelant)alloca
d'une fonctionnalité / piratage non portable à une extension standardisée, mais une perception négative peut persistermalloc
le contrôle explicite demalloc
encourage à penser à la désallocation - si elle est gérée via une fonction wrapper (par exempleWonderfulObject_DestructorFree(ptr)
), la fonction fournit un point pour les opérations de nettoyage de l'implémentation (comme la fermeture des descripteurs de fichiers, la libération de pointeurs internes ou la journalisation) sans modifications explicites du client code: parfois c'est un joli modèle à adopter systématiquementWonderfulObject* p = WonderfulObject_AllocConstructor();
- c'est possible lorsque le "constructeur" est une fonction renvoyant de lamalloc
mémoire (car la mémoire reste allouée après que la fonction retourne la valeur à stockerp
), mais pas si le "constructeur" utilisealloca
WonderfulObject_AllocConstructor
pourrait y parvenir, mais «les macros sont mauvaises» en ce sens qu'elles peuvent entrer en conflit les unes avec les autres et avec du code non macro et créer des substitutions involontaires et des problèmes difficiles à diagnostiquer en conséquencefree
opérations manquantes peuvent être détectées par ValGrind, Purify, etc., mais les appels «destructeurs» manquants ne peuvent pas toujours être détectés du tout - un avantage très ténu en termes d'application de l'utilisation prévue; certainesalloca()
implémentations (telles que GCC) utilisent une macro intégrée pouralloca()
, donc la substitution au moment de l'exécution d'une bibliothèque de diagnostic d'utilisation de la mémoire n'est pas possible de la même manière que pourmalloc
/realloc
/free
(par exemple une clôture électrique)Je sais que cette question est étiquetée C, mais en tant que programmeur C ++, j'ai pensé utiliser C ++ pour illustrer l'utilité potentielle de
alloca
: le code ci-dessous (et ici à ideone ) crée un vecteur de suivi de types polymorphes de tailles différentes qui sont alloués par pile (avec durée de vie liée au retour de la fonction) plutôt que le tas alloué.la source
Toutes les autres réponses sont correctes. Cependant, si la chose que vous souhaitez allouer en utilisant
alloca()
est raisonnablement petite, je pense que c'est une bonne technique qui est plus rapide et plus pratique que l'utilisationmalloc()
ou autre.En d'autres termes,
alloca( 0x00ffffff )
est dangereux et susceptible de provoquer un débordement, exactement autant quechar hugeArray[ 0x00ffffff ];
est. Soyez prudent et raisonnable et tout ira bien.la source
Beaucoup de réponses intéressantes à cette "vieille" question, même des réponses relativement nouvelles, mais je n'en ai trouvé aucune qui mentionne cela ....
J'ai trouvé cette citation dans ... OK, j'ai fait cette citation. Mais vraiment, pensez-y ...
@j_random_hacker a tout à fait raison dans ses commentaires sous d'autres réponses: éviter d'utiliser
alloca()
en faveur de tableaux locaux surdimensionnés ne rend pas votre programme plus sûr contre les débordements de pile (à moins que votre compilateur soit assez vieux pour permettre l'inclusion de fonctions qui utilisent,alloca()
auquel cas vous devriez mise à niveau, ou à moins que vous n'utilisiez desalloca()
boucles internes, auquel cas vous ne devriez pas ... utiliser desalloca()
boucles internes).J'ai travaillé sur des environnements de bureau / serveur et des systèmes embarqués. Beaucoup de systèmes embarqués n'utilisent pas du tout de tas (ils ne lient même pas en support), pour des raisons qui incluent la perception que la mémoire allouée dynamiquement est mauvaise en raison des risques de fuites de mémoire sur une application qui ne redémarre jamais pendant des années à la fois, ou la justification plus raisonnable que la mémoire dynamique est dangereuse car on ne peut pas savoir avec certitude qu'une application ne fragmentera jamais son tas au point d'épuisement de la fausse mémoire. Les programmeurs intégrés se retrouvent donc avec peu d'alternatives.
alloca()
(ou VLA) peut être le bon outil pour le travail.J'ai vu maintes et maintes fois où un programmeur fait un tampon alloué à la pile "assez grand pour gérer n'importe quel cas possible". Dans un arbre d'appels profondément imbriqué, l'utilisation répétée de ce modèle (anti-?) Conduit à une utilisation exagérée de la pile. (Imaginez un arbre d'appels de 20 niveaux de profondeur, où à chaque niveau pour différentes raisons, la fonction suralloue aveuglément un tampon de 1024 octets "juste pour être sûr" alors qu'en général, elle n'en utilisera que 16 ou moins, et seulement les cas rares peuvent en utiliser davantage.) Une alternative consiste à utiliser
alloca()
ou VLA et allouez uniquement autant d'espace de pile que votre fonction a besoin, pour éviter de surcharger inutilement la pile. Espérons que lorsqu'une fonction dans l'arborescence des appels nécessite une allocation plus grande que la normale, d'autres dans l'arborescence des appels utilisent toujours leurs petites allocations normales, et l'utilisation globale de la pile d'applications est nettement inférieure à celle si chaque fonction surallouait aveuglément un tampon local. .Mais si vous choisissez d'utiliser
alloca()
...Sur la base d'autres réponses sur cette page, il semble que les VLA devraient être sûrs (ils ne composent pas les allocations de pile s'ils sont appelés à partir d'une boucle), mais si vous utilisez
alloca()
, veillez à ne pas l'utiliser à l'intérieur d'une boucle et faites assurez- vous que votre fonction ne peut pas être alignée s'il y a une chance qu'elle puisse être appelée dans la boucle d'une autre fonction.la source
alloca()
est vrai, mais on peut en dire autant des fuites de mémoiremalloc()
(pourquoi ne pas utiliser un GC alors? On pourrait argumenter).alloca()
lorsqu'il est utilisé avec soin, il peut être très utile de réduire la taille de la pile.Tout le monde a déjà souligné la grande chose qui est le comportement non défini potentiel d'un débordement de pile, mais je dois mentionner que l'environnement Windows a un excellent mécanisme pour le détecter en utilisant des exceptions structurées (SEH) et des pages de garde. Étant donné que la pile ne s'agrandit que si nécessaire, ces pages de garde résident dans des zones non allouées. Si vous les allouez (en débordant la pile), une exception est levée.
Vous pouvez intercepter cette exception SEH et appeler _resetstkoflw pour réinitialiser la pile et continuer votre joyeux chemin. Ce n'est pas idéal, mais c'est un autre mécanisme pour au moins savoir que quelque chose a mal tourné lorsque le truc frappe le ventilateur. * nix pourrait avoir quelque chose de similaire que je ne connais pas.
Je recommande de limiter la taille maximale de votre allocation en enveloppant alloca et en la suivant en interne. Si vous étiez vraiment inconditionnel à ce sujet, vous pouvez lancer des sentinelles de portée en haut de votre fonction pour suivre les allocations d'allocations dans la portée de la fonction et vérifier la validité par rapport au montant maximum autorisé pour votre projet.
De plus, en plus de ne pas autoriser les fuites de mémoire, alloca ne provoque pas de fragmentation de la mémoire, ce qui est assez important. Je ne pense pas que l'alloca soit une mauvaise pratique si vous l'utilisez intelligemment, ce qui est fondamentalement vrai pour tout. :-)
la source
alloca()
peut exiger tellement d'espace que le pointeur de pile atterrit dans le tas. Avec cela, un attaquant qui peut contrôler la taillealloca()
et les données qui entrent dans ce tampon peut écraser le tas (ce qui est très mauvais).alloca () est agréable et efficace ... mais il est également profondément cassé.
Dans la plupart des cas, vous pouvez le remplacer en utilisant des variables locales et une taille majorante. S'il est utilisé pour de gros objets, les mettre sur le tas est généralement une idée plus sûre.
Si vous en avez vraiment besoin C vous pouvez utiliser VLA (pas de vla en C ++, dommage). Ils sont bien meilleurs que alloca () en ce qui concerne le comportement et la cohérence des portées. Comme je le vois, les VLA sont une sorte d' alloca () bien fait.
Bien sûr, une structure ou un tableau local utilisant un majorant de l'espace nécessaire est encore mieux, et si vous n'avez pas une telle allocation de tas majorant en utilisant plain malloc () est probablement sain. Je ne vois aucun cas d'utilisation sensé où vous avez vraiment vraiment besoin d' alloca () ou de VLA.
la source
alloca
ne crée pas de nom, seulement une plage de mémoire, qui a une durée de vie .alloca
oumalloc
oufree
directement. Je dis des choses comme{stack|heap}_alloc_{bytes,items,struct,varstruct}
et{stack|heap}_dealloc
. Donc,heap_dealloc
juste des appelsfree
etstack_dealloc
c'est un no-op. De cette façon, les allocations de pile peuvent facilement être rétrogradées en allocations de tas, et les intentions sont également plus claires.Voici pourquoi:
Ce n'est pas que quelqu'un écrive ce code, mais l'argument de taille
alloca
auquel vous passez provient presque certainement d'une sorte d'entrée, qui pourrait viser malicieusement à obtenir votre programmealloca
quelque chose d'énorme comme ça. Après tout, si la taille n'est pas basée sur l'entrée ou n'a pas la possibilité d'être grande, pourquoi n'avez-vous pas simplement déclaré un petit tampon local de taille fixe?Pratiquement tout le code utilisant
alloca
et / ou vlas C99 comporte de graves bogues qui entraîneront des plantages (si vous avez de la chance) ou des compromis de privilèges (si vous n'êtes pas aussi chanceux).la source
alloca
. Vous avez dit que presque tout le code qui l'utilise avait un bug, mais je prévoyais de l'utiliser; j'ignorerais normalement une telle affirmation, mais à venir je ne vais pas. J'écris une machine virtuelle et j'aimerais allouer des variables qui n'échappent pas à la fonction sur la pile, au lieu de dynamiquement, à cause de l'énorme accélération. Y a-t-il une alternative approche qui a les mêmes caractéristiques de performance? Je sais que je peux me rapprocher des pools de mémoire, mais ce n'est toujours pas aussi bon marché. Que feriez-vous?*0 = 9;
incroyable! Je suppose que je ne devrais jamais utiliser de pointeurs (ou du moins les déréférencer). Euh, attends. Je peux tester pour voir si elle est nulle. Hmm. Je suppose que je peux également tester la taille de la mémoire que je veux allouer viaalloca
. Homme bizarre. Bizarre.*0=9;
n'est pas valide C. Quant au test de la taille à laquelle vous passezalloca
, testez-le par rapport à quoi? Il n'y a aucun moyen de connaître la limite, et si vous allez simplement la tester par rapport à une petite taille fixe sûre connue (par exemple 8k), vous pourriez tout aussi bien utiliser un tableau de taille fixe sur la pile.small_constant * log(user_input)
nous avons probablement suffisamment de mémoire.Je ne pense pas que quiconque ait mentionné cela: l'utilisation d'alloca dans une fonction gênera ou désactivera certaines optimisations qui pourraient autrement être appliquées dans la fonction, car le compilateur ne peut pas connaître la taille du cadre de pile de la fonction.
Par exemple, une optimisation courante par les compilateurs C consiste à éliminer l'utilisation du pointeur de trame dans une fonction, les accès aux trames sont effectués par rapport au pointeur de pile à la place; il y a donc un autre registre à usage général. Mais si alloca est appelé dans la fonction, la différence entre sp et fp sera inconnue pour une partie de la fonction, donc cette optimisation ne peut pas être effectuée.
Compte tenu de la rareté de son utilisation et de son statut louche en tant que fonction standard, les concepteurs de compilateurs désactivent très probablement toute optimisation qui pourrait causer des problèmes avec alloca, si cela prendrait plus qu'un petit effort pour le faire fonctionner avec alloca.
MISE À JOUR: Étant donné que des tableaux locaux de longueur variable ont été ajoutés à C et que ceux-ci présentent des problèmes de génération de code très similaires au compilateur en tant qu'alloca, je vois que la `` rareté d'utilisation et le statut ombragé '' ne s'appliquent pas au mécanisme sous-jacent; mais je soupçonnerais toujours que l'utilisation de alloca ou VLA tend à compromettre la génération de code au sein d'une fonction qui les utilise. Je serais heureux de recevoir les commentaires des concepteurs de compilateurs.
la source
Un écueil
alloca
est quelongjmp
cela rembobine.Autrement dit, si vous enregistrez un contexte avec
setjmp
, puis de laalloca
mémoire, puislongjmp
dans le contexte, vous risquez de perdre laalloca
mémoire. Le pointeur de pile est de retour où il était et donc la mémoire n'est plus réservée; si vous appelez une fonction ou en faites une autrealloca
, vous encombrerez l'originalalloca
.Pour clarifier, ce à quoi je fais spécifiquement référence ici est une situation dans laquelle
longjmp
il ne revient pas de la fonction où il aalloca
eu lieu! Au contraire, une fonction enregistre le contexte avecsetjmp
; alloue ensuite de la mémoire avecalloca
et enfin un longjmp a lieu dans ce contexte. Laalloca
mémoire de cette fonction n'est pas entièrement libérée; juste toute la mémoire qu'il a allouée depuis lesetjmp
. Bien sûr, je parle d'un comportement observé; aucune exigence de ce genre n'est documentée àalloca
ma connaissance.Dans la documentation, l'accent est généralement mis sur le concept selon lequel la
alloca
mémoire est associée à une activation de fonction , et non à un bloc; que plusieurs invocations dealloca
simplement saisir plus de mémoire de pile qui est tout libéré lorsque la fonction se termine. Pas si; la mémoire est en fait associée au contexte de la procédure. Lorsque le contexte est restauré aveclongjmp
, il en est de même de l'alloca
état antérieur . C'est une conséquence du registre du pointeur de pile lui-même utilisé pour l'allocation, et également (nécessairement) enregistré et restauré dans lejmp_buf
.Soit dit en passant, cela, s'il fonctionne de cette façon, fournit un mécanisme plausible pour libérer délibérément la mémoire allouée avec
alloca
.J'ai rencontré cela comme la cause première d'un bug.
la source
longjmp
retourne et rend donc les oublie programme sur tout ce qui est arrivé dans la pile: toutes les variables, les appels de fonction , etc. Etalloca
est comme un tableau sur la pile, il est donc prévu qu'ils seront soient faussés comme tout le reste sur la pile.man alloca
a donné la phrase suivante: "Parce que l'espace alloué par alloca () est alloué dans le cadre de la pile, cet espace est automatiquement libéré si le retour de la fonction est sauté par un appel à longjmp (3) ou siglongjmp (3).". Il est donc documenté que la mémoire allouée àalloca
est détruite après alongjmp
.longjmp
. La fonction cible n'est pas encore retournée. Il l'a faitsetjmp
,alloca
et puislongjmp
. Lelongjmp
peut revenir en arrière lealloca
dos de l' Etat à ce qu'il était ausetjmp
temps. C'est-à-dire que le pointeur déplacé paralloca
souffre du même problème qu'une variable locale qui n'a pas été marquéevolatile
!setjmp
alorsalloca
, puislongjmp
, il est normal quealloca
serait rembobinées. Le butlongjmp
est de revenir à l'état dans lequel il a été enregistrésetjmp
!Un endroit où
alloca()
est particulièrement dangereux quemalloc()
le noyau - le noyau d'un système d'exploitation typique a un espace de pile de taille fixe codé en dur dans l'un de ses en-têtes; il n'est pas aussi flexible que la pile d'une application. Faire un appel àalloca()
avec une taille non garantie peut entraîner le plantage du noyau. Certains compilateurs avertissent l'utilisation dealloca()
(et même des VLA d'ailleurs) sous certaines options qui doivent être activées lors de la compilation d'un code de noyau - ici, il est préférable d'allouer de la mémoire dans le tas qui n'est pas fixée par une limite codée en dur.la source
alloca()
n'est pas plus dangereux queint foo[bar];
oùbar
est un entier arbitraire.Si vous écrivez accidentellement au-delà du bloc alloué avec
alloca
(en raison d'un débordement de tampon par exemple), alors vous écraserez l' adresse de retour de votre fonction, car celle-ci est située "au-dessus" de la pile, c'est- à- dire après votre bloc alloué.La conséquence en est double:
Le programme se bloquera de façon spectaculaire et il sera impossible de dire pourquoi ou où il s'est bloqué (la pile se déroulera très probablement vers une adresse aléatoire en raison du pointeur de trame écrasé).
Cela rend le débordement de tampon beaucoup plus dangereux, car un utilisateur malveillant peut créer une charge utile spéciale qui serait placée sur la pile et peut donc être exécutée.
En revanche, si vous écrivez au-delà d'un bloc sur le tas, vous obtenez «juste» une corruption de tas. Le programme se terminera probablement de façon inattendue mais déroulera la pile correctement, réduisant ainsi les risques d'exécution de code malveillant.
la source
alloca
.alloca
par rapport àmalloc
(donc pas de tampon de taille fixe sur la pile).Malheureusement, le vraiment génial
alloca()
manque dans le tcc presque génial. Gcc aalloca()
.Il sème la graine de sa propre destruction. Avec retour comme destructeur.
Comme
malloc()
s'il retourne un pointeur invalide en cas d'échec qui se produira par défaut sur les systèmes modernes avec une MMU (et, espérons-le, redémarrera ceux qui n'en ont pas).Contrairement aux variables automatiques, vous pouvez spécifier la taille au moment de l'exécution.
Cela fonctionne bien avec la récursivité. Vous pouvez utiliser des variables statiques pour obtenir quelque chose de similaire à la récursivité de queue et utiliser seulement quelques autres informations de passage à chaque itération.
Si vous poussez trop profondément, vous êtes assuré d'un défaut de segmentation (si vous avez une MMU).
Notez qu'il
malloc()
n'en offre pas plus car il retourne NULL (qui sera également un défaut de segmentation s'il est attribué) lorsque le système est à court de mémoire. C'est-à-dire que tout ce que vous pouvez faire est de cautionner ou simplement essayer de l'attribuer de quelque façon que ce soit.Pour utiliser,
malloc()
j'utilise des globaux et je les attribue NULL. Si le pointeur n'est pas NULL, je le libère avant de l'utilisermalloc()
.Vous pouvez également utiliser
realloc()
comme cas général si vous souhaitez copier des données existantes. Vous devez vérifier le pointeur avant de déterminer si vous allez copier ou concaténer après lerealloc()
.3.2.5.2 Avantages de alloca
la source
Les processus ne disposent que d'une quantité limitée d'espace de pile disponible, bien inférieure à la quantité de mémoire disponible
malloc()
.En utilisant,
alloca()
vous augmentez considérablement vos chances d'obtenir une erreur de débordement de pile (si vous avez de la chance, ou un plantage inexplicable si vous ne l'êtes pas).la source
Pas très joli, mais si les performances comptent vraiment, vous pouvez préallouer de l'espace sur la pile.
Si vous avez déjà la taille maximale du bloc de mémoire dont vous avez besoin et que vous souhaitez conserver les vérifications de débordement, vous pouvez faire quelque chose comme:
la source
La fonction alloca est géniale et tous les opposants répandent simplement du FUD.
Array et parray sont EXACTEMENT les mêmes avec EXACTEMENT les mêmes risques. Dire que l'un est meilleur qu'un autre est un choix syntaxique et non technique.
En ce qui concerne le choix des variables de pile par rapport aux variables de tas, il y a BEAUCOUP d'avantages aux programmes de longue durée utilisant la pile sur le tas pour les variables avec des durées de vie in-scope. Vous évitez la fragmentation du tas et vous pouvez éviter d'agrandir votre espace de processus avec de l'espace de tas inutilisé (inutilisable). Vous n'avez pas besoin de le nettoyer. Vous pouvez contrôler l'allocation de pile sur le processus.
Pourquoi est-ce mauvais?
la source
En fait, alloca n'est pas garanti d'utiliser la pile. En effet, l'implémentation gcc-2.95 d'alloca alloue de la mémoire à partir du tas en utilisant malloc lui-même. De plus, cette implémentation est boguée, elle peut entraîner une fuite de mémoire et un comportement inattendu si vous l'appelez à l'intérieur d'un bloc avec une nouvelle utilisation de goto. Non, pour dire que vous ne devriez jamais l'utiliser, mais parfois, alloca entraîne plus de frais généraux qu'il n'en libère.
la source
alloca
. Comment aurait-il nettoyé la mémoire lorsqu'illongjmp
est utilisé pour abandonner les trames qui l'ont faitalloca
? Quand est-ce que quelqu'un utiliserait gcc 2.95 aujourd'hui?À mon humble avis, alloca est considéré comme une mauvaise pratique car tout le monde a peur d'épuiser la limite de taille de pile.
J'ai beaucoup appris en lisant ce fil et quelques autres liens:
J'utilise alloca principalement pour rendre mes fichiers C simples compilables sur msvc et gcc sans aucune modification, style C89, pas de #ifdef _MSC_VER, etc.
Merci ! Ce fil m'a fait m'inscrire à ce site :)
la source
À mon avis, alloca (), lorsqu'elle est disponible, ne doit être utilisée que de manière contrainte. Tout comme l'utilisation de "goto", un assez grand nombre de personnes par ailleurs raisonnables ont une forte aversion non seulement pour l'utilisation de alloca (), mais aussi pour son existence.
Pour une utilisation intégrée, où la taille de la pile est connue et où des limites peuvent être imposées via la convention et l'analyse de la taille de l'allocation, et où le compilateur ne peut pas être mis à niveau pour prendre en charge C99 +, l'utilisation de alloca () est très bien, et j'ai été connu pour l'utiliser.
Lorsqu'ils sont disponibles, les VLA peuvent avoir certains avantages par rapport à alloca (): le compilateur peut générer des vérifications de limites de pile qui intercepteront l'accès hors limites lorsque l'accès au style de tableau est utilisé (je ne sais pas si des compilateurs le font, mais il peut et l'analyse du code peut déterminer si les expressions d'accès au tableau sont correctement délimitées. Notez que, dans certains environnements de programmation, tels que l'automobile, les équipements médicaux et l'avionique, cette analyse doit être effectuée même pour les baies de taille fixe, à la fois automatique (sur la pile) et statique (globale ou locale).
Sur les architectures qui stockent à la fois des données et des adresses de retour / pointeurs de trame sur la pile (d'après ce que je sais, c'est tout), toute variable allouée à la pile peut être dangereuse car l'adresse de la variable peut être prise et des valeurs d'entrée non contrôlées peuvent permettre toutes sortes de méfaits.
La portabilité est moins préoccupante dans l'espace intégré, mais c'est un bon argument contre l'utilisation de alloca () en dehors de circonstances soigneusement contrôlées.
En dehors de l'espace intégré, j'ai utilisé alloca () principalement à l'intérieur des fonctions de journalisation et de formatage pour plus d'efficacité, et dans un scanner lexical non récursif, où des structures temporaires (allouées en utilisant alloca () sont créées lors de la tokenisation et de la classification, puis une persistance l'objet (alloué via malloc ()) est rempli avant le retour de la fonction. L'utilisation d'alloca () pour les petites structures temporaires réduit considérablement la fragmentation lorsque l'objet persistant est alloué.
la source
La plupart des réponses manquent ici: il y a une raison pour laquelle utiliser
_alloca()
est potentiellement pire que de simplement stocker de gros objets dans la pile.La principale différence entre le stockage automatique et le
_alloca()
fait que ce dernier souffre d'un problème supplémentaire (grave): le bloc alloué n'est pas contrôlé par le compilateur , il n'y a donc aucun moyen pour le compilateur de l'optimiser ou de le recycler.Comparer:
avec:
Le problème avec ce dernier devrait être évident.
la source
alloca
(oui, je dis bien VLA, car ilalloca
est plus qu'un simple créateur de tableaux de taille statique)?Je ne pense pas que quiconque ait mentionné cela, mais alloca a également de sérieux problèmes de sécurité qui ne sont pas nécessairement présents avec malloc (bien que ces problèmes surviennent également avec les tableaux basés sur la pile, dynamiques ou non). Étant donné que la mémoire est allouée sur la pile, les débordements / débordements de tampon ont des conséquences beaucoup plus graves qu'avec un simple malloc.
En particulier, l'adresse de retour d'une fonction est stockée sur la pile. Si cette valeur est corrompue, votre code pourrait être envoyé à n'importe quelle région exécutable de la mémoire. Les compilateurs se donnent beaucoup de mal pour rendre cela difficile (en particulier en randomisant la disposition des adresses). Cependant, c'est clairement pire qu'un simple débordement de pile car le meilleur des cas est un SEGFAULT si la valeur de retour est corrompue, mais il pourrait également commencer à exécuter un morceau de mémoire aléatoire ou dans le pire des cas une région de mémoire qui compromet la sécurité de votre programme .
la source