Comment empêchez-vous des tableaux de longueur variable de tomber en panne quand il n'y a pas assez de mémoire?

StackOverflow https://stackoverflow.com/questions/4151172

  •  08-10-2019
  •  | 
  •  

Question

Avant de tableaux de longueur variable ont été pris en charge, je les allouer dynamiquement comme ceci:

int foo(size_t n)
{
    int *arr = malloc(n * sizeof int);
    if (!arr) return ENOMEM; /* not enough memory */
    .
    . else do stuff with arr[]
    .
    free(arr);
    return 0;
}

Avec des tableaux de longueur variable, je peux maintenant le faire paraître plus propre:

int bar(size_t n)
{
    int arr[n];
    .
    . do stuff with arr[]
    .
    return 0;
}

Mais maintenant je n'ai pas "de mémoire" de vérification. En fait, le programme se bloque si n est trop grand.

Comment puis-je gracieusement sous caution de la barre (n) si n est trop grand?

Était-ce utile?

La solution

La situation est exactement inchangé par rapport à toutes les autres variables locales - une déclaration comme ceci:

int baz(void)
{
    int arr[100000];
    .
    . do stuff with arr[]
    .
    return 0;
}

a exactement le même problème. La « solution » est le même que celui a toujours été - ne pas recurse trop profondément, et ne pas allouer de très grandes structures de données avec la durée de stockage automatique (continuer à utiliser malloc() pour ces cas). La valeur de « très grande » dépend fortement de votre environnement.

En d'autres termes, ne pas déclarer int array[n]; sauf si vous savez que n est limitée à une valeur raisonnable, de sorte que vous auriez été heureux de déclarer un tableau de cette taille maximale comme ordinaire, un tableau de type non-variablement modifié .

(Oui, cela signifie que des réseaux de type variablement modifiés ne sont pas aussi utiles qu'elles apparaissent d'abord, puisque vous gagnez très peu plus juste de déclarer le tableau à la taille maximale nécessaire).

Autres conseils

Vous pouvez les empêcher de se briser en ne les utilisant. :)

En toute sincérité, il n'y a presque pas de moyen sûr d'utiliser des tableaux de longueur variable pour rendre votre vie plus facile à moins que vous avez des limites fortes sur la taille. D'autre part, vous pouvez les utiliser sous condition, de manière à ceci:

char vla_buf[n < 1000 ? n : 1];
char *buf = sizeof vla_buf < n ? malloc(n) : vla_buf;
if (!buf) goto error;
/* ... Do stuff with buf ... */
if (buf != vla_buf) free(buf);

Bien que cela ressemble à la douleur inutile, il peut faire une énorme différence de performances, en particulier dans les applications threadées où de nombreux appels à malloc et free pourraient entraîner des conflits de verrouillage. (Un autre avantage notable de cette astuce est que vous pouvez soutenir les anciens compilateurs sans VLA en remplaçant simplement [n < 1000 ? n : 1] avec 1000, par exemple avec une macro.)

Un autre cas obscur où VLA peut être utile est dans les algorithmes récursifs où vous connaissez le nombre total d'entrées de tableau nécessaires à tous les niveaux de récursivité est limitée par n, où n est assez petit que vous êtes confiant, il ne débordera pas la pile, mais où il pourrait y avoir jusqu'à des niveaux de n des niveaux récursivité et individuels qui utilisent jusqu'à éléments n. Avant C99, la seule façon de traiter ce cas sans prendre l'espace de pile de n^2 était d'utiliser malloc. Avec Vlas, vous pouvez résoudre le problème tout à fait sur la pile.

Gardez à l'esprit, ces cas où VLA sont vraiment bénéfiques sont sacrément rares. Normalement VLA est juste une façon de vous tromper que la gestion de la mémoire est facile, jusqu'à ce que vous obtenez peu les vulnérabilités résultant (à trivial exploit) que vous avez créé. : -)

Modifier Pour mieux répondre la question initiale de l'OP:

#define MAX_VLA 10000
int bar(size_t n)
{
    int arr[n <= MAX_VLA ? n : 1];
    if (sizeof arr/sizeof *arr < n) return ENOMEM;
    /* ... */
    return 0;
}

En réalité, il est extrêmement coûteux de vérifier les conditions de mémoire partout. La façon de enterprisy pour traiter des données massives est de la taille des données limite en définissant la taille limite absolue au point de contrôle unique et début échec rapide et avec élégance lorsque le bouchon est frappé.

Ce que je viens de le suggérer est simple et stupide. Mais ce que tout son produit ordinaire (non-scientifique ou spécial) fait toujours. Et sa ce qui est normalement attendu par le client.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top