Pourquoi bad_alloc () exception levée en cas de size_t

Je travaille sur le morceau de code ci-dessous et quand std::bad_alloc ce code, std::bad_alloc exception std::bad_alloc :

 int _tmain(int argc, _TCHAR* argv[]) { FILE * pFile; size_t state; pFile = fopen("C:\\shared.tmp", "rb"); if (pFile != NULL) { size_t rt = fread(&state, sizeof(int), 1, pFile); char *ssortingng = NULL; ssortingng= new char[state + 1]; fclose(pFile); } return 0; } 

Cette ligne ci-dessous provoque une exception:

 ssortingng = new char[state + 1]; 

Pourquoi cela se produit et comment puis-je résoudre ce problème?

Vous passez l’adresse d’une variable non initialisée de 64 bits (8 octets, sur les systèmes 64 bits modernes), et dites à fread de lire sizeof(int) (32 bits, 4 octets sur ces mêmes systèmes) octets de la fichier dans cette variable.

Cela écrasera 4 octets de la variable avec la valeur lue, mais laissera les 4 autres non initialisés. Les 4 octets qu’il écrase dépendent de l’architecture (le moins significatif sur les processeurs Intel, le plus significatif sur les ARM configurés en mode big endian), mais le résultat sera probablement anormal, car 4 octets n’ont pas été initialisés et peuvent contenir quelque chose .

Dans votre cas, il s’agit très probablement des octets les plus significatifs et contiennent au moins un bit non nul, ce qui signifie que vous essayez d’allouer bien au-delà de 4 Go de mémoire, ce que vous n’avez pas.

La solution est de rendre l’ state std::uint32_t (puisque vous vous attendez à ce que le fichier contienne 4 octets représentant un entier non signé; n’oubliez pas d’inclure ) et passez sizeof(std::uint32_t) , et en général Assurez-vous que pour chaque appel de même type, lorsque vous passez un pointeur et une taille, assurez-vous que la taille du pointeur correspond exactement à celle que vous passez. Passer un size_t* et sizeof(int) ne répond pas à ces exigences sur les systèmes 64 bits, et comme la taille des types de base de C ++ n’est pas garantie, vous ne voulez généralement pas les utiliser pour les E / S binarys.

Il y a plusieurs choses que vous pouvez améliorer dans votre code C ++, mais il y a plusieurs raisons pour lesquelles vous vous retrouvez avec ce comportement:

Tout d’abord, l’ state la variable est de type size_t , mais votre code tente d’initialiser sa valeur à l’aide de fread(&state, sizeof(int), 1, pFile); . Maintenant, si sizeof(state) != sizeof(int) vous avez un comportement indéfini. Si sizeof(state) < sizeof(int) , alors l'instruction fread écrase généralement de la mémoire arbitraire après le stockage pour l' state variable. Cela conduit à un comportement indéfini (par exemple, l' state peut avoir une grande valeur aléatoire et l'atsortingbution échoue).

Deuxièmement, si sizeof(state) > sizeof(int) , l' state n'est que partiellement initialisé et sa valeur réelle dépend à la fois des bits initialisés (par fread ) et non initialisés. Sa valeur peut donc être un grand nombre et l’allocation peut échouer.

Troisièmement, le if sizeof(state) == sizeof(int) alors il se peut que la valeur lue soit trop grande et que l'allocation échoue simplement parce que vous manquez de mémoire.

Quasortingèmement, la valeur que vous lisez dans le fichier peut avoir un codage ou une endianness différent. Par exemple, si la valeur a été écrite dans le fichier au format big-endian, mais est fread sur un processeur peu endian, les octets risquent d'être mal échangés. Vous devrez peut-être échanger les octets avant d'utiliser la valeur lue.

Je vous suggère d’utiliser à la place un type entier à largeur fixe de (ou pour pré-C ++ 11), tel que std::uint64_t pour l’ state variable, lire la valeur avec fread(&state, sizeof(state), 1, pFile); , puis état d'octet-swap si la qualité de votre CPU ne correspond pas à la valeur de la valeur stockée dans le fichier.

Vous devez décider du nombre maximum de caractères que vous souhaitez atsortingbuer et de la sortie d’erreur si l’ state est supérieur à celui-ci. Presque certainement, c’est le cas.