2016-09-29 1 views
0

Voici un code que j'ai écrit pour le compilateur GCC.Comportement intéressant de malloc()

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int *p; 
    p = (int *)malloc(9 * sizeof(char)); 
    p[0] = 2147483647; 
    p[1] = 2147483647; 
    p[2] = 1025; 
    printf("%d, %d, %d, %d\n", sizeof(char), *(p), *(p+1), *(p+2)); 
} 

La sortie est la suivante:

1, 2147483647, 2147483647, 1025 

Ma question est, bien que je n'a alloué que 9 octets au pointeur, il semble utiliser tous les 12 octets. Le résultat est le même (sauf un avertissement de compilateur), si je lance (char *) au lieu de (int *). L'attribution de malloc() est-elle complète? c'est-à-dire qu'il alloue toujours en multiples de Data Type du pointeur, indépendamment de ce que nous avons alloué? ou est-ce spécifique à la mise en œuvre?

+2

Les bits doivent-ils être en octets? PS - Vous n'avez pas besoin de la distribution. –

+0

Vous avez fait quelque chose de non légal et personne n'a remarqué. Est-ce que cela le rend légal? –

+0

Merci. J'ai corrigé –

Répondre

7
p = (int *)malloc(9 * sizeof(char)); 

Ce que vous faites est undefined behavior si la taille de l'entier est de 4 octets. Parce que vous avez alloué 9 octets et utilisé 12.

Coulée n'a aucun effet, en fait vous ne devriez pas jeter le résultat de malloc en C du tout.

Un autre endroit où vous déclenchez un comportement non défini utilise le spécificateur de format erroné pour sizeof, vous devez utiliser %zu au lieu de %d dans printf (pour sizeof).

+0

Merci. Devrais-je le corriger? –

+1

@UmeshCG Bien sûr, vous devriez. (lire aussi le lien fourni) –

+0

Le spécificateur de format correct pour 'sizeof' est' "% zu" ', car il est non signé. – mch

1

Le fait que vous ayez pu écrire dans les octets «supplémentaires» ne signifie pas qu'ils vous ont été attribués; cela signifie simplement qu'ils existent. Vous n'avez aucune raison de vous attendre à ce que ces octets ne changent pas "magiquement" dans le futur, puisque vous ne les avez pas alloués, et si un autre code le faisait, ils pourraient changer (et, contrairement à votre code, le faire légitimement).

+0

Vous voulez dire que ce n'est pas légitime et j'ai de la chance que le programme ne plante pas? –

+2

@UmeshCG Je dirais, malchanceux. –

3

Comme d'autres l'ont mentionné, vous écrivez après la fin d'un tampon mallocé. Ceci appelle undefined behavior.

Ce comportement non défini signifie que tout peut arriver. Le programme peut tomber en panne, il peut donner des résultats inattendus, ou (dans ce cas) il semble fonctionner correctement.

Faire un changement de code apparemment sans rapport pourrait faire que votre programme se bloque soudainement.

Pour illustrer ce qui se passe, voici la sortie de l'exécution de votre programme sous valgrind:

[dbush] valgrind /tmp/x1 
==19430== Memcheck, a memory error detector 
==19430== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. 
==19430== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info 
==19430== Command: /tmp/x1 
==19430== 
==19430== Invalid write of size 4 
==19430== at 0x40050E: main (x1.c:11) 
==19430== Address 0x4c18048 is 8 bytes inside a block of size 9 alloc'd 
==19430== at 0x4A0610C: malloc (vg_replace_malloc.c:195) 
==19430== by 0x4004E9: main (x1.c:8) 
==19430== 
==19430== Invalid read of size 4 
==19430== at 0x40051C: main (x1.c:12) 
==19430== Address 0x4c18048 is 8 bytes inside a block of size 9 alloc'd 
==19430== at 0x4A0610C: malloc (vg_replace_malloc.c:195) 
==19430== by 0x4004E9: main (x1.c:8) 
==19430== 
1, 2147483647, 2147483647, 1025 
==19430== 
==19430== HEAP SUMMARY: 
==19430==  in use at exit: 9 bytes in 1 blocks 
==19430== total heap usage: 1 allocs, 0 frees, 9 bytes allocated 
==19430== 
==19430== LEAK SUMMARY: 
==19430== definitely lost: 9 bytes in 1 blocks 
==19430== indirectly lost: 0 bytes in 0 blocks 
==19430==  possibly lost: 0 bytes in 0 blocks 
==19430== still reachable: 0 bytes in 0 blocks 
==19430==   suppressed: 0 bytes in 0 blocks 
==19430== Rerun with --leak-check=full to see details of leaked memory 
==19430== 
==19430== For counts of detected and suppressed errors, rerun with: -v 
==19430== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4) 

Vous pouvez voir cette sortie que vous lisez et écrit après la fin de votre mémoire tampon allouée.

+0

Merci pour la démonstration! –

1

En C, les pointeurs peuvent accéder à n'importe quelle mémoire. Dans votre code, vous avez alloué seulement 9 octets. Comme le langage C n'offre pas de vérification liée, vous pouvez simplement déplacer votre pointeur vers n'importe quel emplacement. Mais cela ne signifie pas que vous avez le contrôle sur ces emplacements de mémoire. Il peut en résulter sigsegv, crash de l'application ou AccessViolationException (si ce code est utilisé nativement par un autre langage comme C# ou Java). En outre, ces octets peuvent être modifiés par un autre programme qui peut corrompre vos données.