Pourquoi est-ce une fonction C se planter à fclose?
S'il vous plaît aidez-moi à comprendre pourquoi cette fonction déclenche une exception lorsqu'il atteint fclose :
void receive_file(int socket, char *save_to, int file_size) {
FILE *handle = fopen(save_to,"wb");
if(handle != NULL) {
int SIZE = 1024;
char buffer[SIZE];
memset(buffer,0,SIZE);
int read_so_far = 0;
int read_now = 0;
int reading_unit = (file_size < SIZE) ? file_size : SIZE;
do {
read_now = read(socket,buffer,reading_unit);
fwrite(buffer,read_now,1,handle);
read_so_far += read_now;
if(read_so_far >= file_size) {
break;
}
memset(buffer, 0, sizeof(buffer));
} while (1);
read_now = 0;
fclose(handle);
}
else {
extern int errno;
printf("error creating file");
printf(" error code : %d",errno);
exit(-1);
}
}
Eclipse CDT existe avec l'erreur suivante :
Le pas à pas jusqu'à la sortie de la fonction __kernel_vsyscall, qui n'a pas de numéro de ligne de l'information.
Le but de cette fonction est de recevoir un fichier via une socket.
EDIT: je suis sous CentOS 5.3. Le truc, c'est que le fichier est créé et écrit. Même le MD5 est correct. Je ne comprends pas pourquoi il est en situation d'échec fclose.
EDIT2: voici une trace de la pile, j'ai réussi à obtenir :
*** glibc détecté *** /home/linuser/espace de travail/proj/Debug/proj: free(): invalid suivant la taille (normal): 0x096a0068 *** ======= Backtrace: ========= /lib/libc.donc.6[0x4fb0f1] /lib/libc.donc.6(bgratuit+0x90)[0x4febc0] /lib/libc.donc.6(fclose+0x136)[0x4e9c56] /home/linuser/espace de travail/proj/Debug/proj[0x8048cd8] /home/linuser/espace de travail/proj/Debug/proj[0x80492d6] /home/linuser/espace de travail/proj/Debug/proj[0x804963d] /lib/libc.donc.6(__libc_start_principaux+0xdc)[0x4a7e8c] /home/linuser/espace de travail/proj/Debug/proj[0x8048901] ======= Carte mémoire: ======== 001ff000-00200000 r-xp 001ff000 00:00 0 [vdso] 0046f000-00489000 r-xp 00000000 08:06 1280361 /lib/ld-2.5.donc 00489000-0048a000 r-xp 00019000 08:06 1280361 /lib/ld-2.5.donc 0048a000-0048b000 rwxp 0001a000 08:06 1280361 /lib/ld-2.5.donc 00492000-005d0000 r-xp 00000000 08:06 1280362 /lib/libc-2.5.donc 005d0000-005d2000 r-xp 0013e000 08:06 1280362 /lib/libc-2.5.donc 005d2000-005d3000 rwxp 00140000 08:06 1280362 /lib/libc-2.5.donc 005d3000-005d6000 rwxp 005d3000 00:00 0 005d8000-005fd000 r-xp 00000000 08:06 1280369 /lib/libm-2.5.donc 005fd000-005fe000 r-xp 00024000 08:06 1280369 /lib/libm-2.5.donc 005fe000-005ff000 rwxp 00025000 08:06 1280369 /lib/libm-2.5.donc 009b2000-009bd000 r-xp 00000000 08:06 1280372 /lib/libgcc_s-4.1.2-20080825.donc.1 009bd000-009be000 rwxp 0000a000 08:06 1280372 /lib/libgcc_s-4.1.2-20080825.donc.1 009c5000-00aa5000 r-xp 00000000 08:06 5465873 /usr/lib/libstdc++.donc.6.0.8 00aa5000-00aa9000 r-xp 000df000 08:06 5465873 /usr/lib/libstdc++.donc.6.0.8 00aa9000-00aaa000 rwxp 000e3000 08:06 5465873 /usr/lib/libstdc++.donc.6.0.8 00aaa000-00ab0000 rwxp 00aaa000 00:00 0 08048000-0804a000 r-xp 00000000 08:06 4884214 /home/linuser/espace de travail/proj/Debug/proj 0804a000-0804b000 rw-p 00001000 08:06 4884214 /home/linuser/espace de travail/proj/Debug/proj 096a0000-096c1000 rw-p 096a0000 00:00 0 [tas] b7e00000-b7e21000 rw-p b7e00000 00:00 0 b7e21000-b7f00000 ---p b7e21000 00:00 0 b7f99000-b7f9a000 rw-p b7f99000 00:00 0 b7faa000-b7fac000 rw-p b7faa000 00:00 0 bfa82000-bfa97000 rw-p bffea000 00:00 0 [pile]
et voici la "mise à jour" de la version de la fonction :
void rec_file(int socket,char *path,int size)
{
FILE *handle = fopen(path,"wb");
char buffer[4096];
int total_read = 0;
if(handle != NULL)
{
while(1)
{
int bytes_read = recv(socket,buffer,4096,0);
total_read += bytes_read;
if(bytes_read != -1)
{
fwrite(buffer,bytes_read,1,handle);
}
else
{
printf("read error ");
exit(-1);
}
if(total_read >= size)
{
break;
}
}
fclose(handle);
}
else
{
printf("error receiving file");
exit(-1);
}
}
c'est peut-être plus propre? Cependant, je continue à recevoir les mêmes fclose exception.
EDIT3:
J'ai commenté tout et je n'ai plus quitté le code suivant, qui, malheureusement, jette toujours l'exception à la fonction fclose :
void nrec(int sock,char* path,int size)
{
FILE *handle = fopen(path,"wb");
if(handle == NULL)
{
printf ("error opening file");
return;
}
fclose(handle);
}
- Ne pas écrire " extern int errno;' -- utiliser #include <errno.h>; parce que "errno" est modifiable entier l-valeur, mais pas nécessairement un int. En multi-thread de programmation, il est habituellement #define errno *(errno_func()) où extern int *errno_func(void);
- Avez-vous exclu que save_to (le nom du fichier que vous souhaitez écrire) n'est pas la poubelle? Aussi, ce système d'exploitation?
- Le memset() les opérations ne sont pas vraiment nécessaires.
- Aussi, à l'aide d'un VLA est ... inhabituel et inutiles dans le contexte. Vous devez être conscient que c'est un C99 construire.
- Un de plus: l'écriture si bytes_read est supérieure à zéro.
- Vous gardez en disant: "lève une exception" - que voulez-vous dire de la baie qui? Êtes-vous à l'aide de C ou C++? Dans les deux cas une exception ne doit jamais être jeté par un appel à la fonction fclose().
- Je me suis habitué à la programmation orientée objet de la terminologie. Pensez à cela comme une erreur d'exécution, si cela aide.
Vous devez vous connecter pour publier un commentaire.
la fonction fclose() renvoie une valeur: 0 si le fichier est fermé avec succès, EOF si pas. Envisager de modifier votre code pour ...
if (fclose(handle)) { printf("erreur à la fermeture du fichier."); exit(-1); }
Comme tout le monde le souligne, vérifier read() pour l'erreur.
Si l'incident se passe après le fclose renvoie 0 (succès), et tous les lire()s ont été couronnées de succès, alors peut-être que le problème est ailleurs. C'est peut-être le VLA. Envisager de changer le tampon de code dans un fichier statique ou un malloc /free.
Si l'appelant s'est trompé sur la taille du fichier, disons, et a réclamé le fichier a été de 500 octets, alors qu'en fait c'est seulement 480, votre code de garder la lecture de la douille pour toujours?
Ce code semble très incertain ... sur lui-même. Beaucoup de inutile affectations,
memset()
appels, de logique compliquée.Il n'y a pas de limiter le montant que vous essayez de lire. Toujours lire autant que vous avez de l'espace de mémoire tampon pour; s'il y a moins de données disponibles, vous obtiendrez moins de.
Il également ne pas gérer correctement les erreurs. Si
read()
échoue, il peut renvoyer -1, dans lequel cas de Mauvaises Choses(TM) qui va se passer toute la place.Mon conseil serait de le nettoyer, réfléchir sur les valeurs de retour de fonctions d'e/S et de les vérifier de mieux, puis essayez à nouveau.
À défaut, si vous êtes sous Linux, exécutez à travers Valgrind pour obtenir de l'aide au suivi de la panne.
Pas sûr, mais vous savez que lire() peut retourner un négatif en cas d'erreur, non?
Vous n'avez pas de vérifier si vous avez obtenu une indication d'erreur à partir de la
read()
appel. Si vous obtenez un -1 à partir deread()
, vous de le passer à, de manière incontrôlée, àfwrite()
, qui prend unesize_t
comme argument. Lorsque votreint
valeur est convertie àsize_t
(ou considéré commesize_t
), il devient un assez grand nombre (4 GO - 1 sur un système 32-bits). Donc,fwrite()
fait comme vous commande essaie d'écrire un grand nombre de données à partir d'endroits, il n'est pas censé le faire.Vous avez besoin de tester la valeur de retour de read() - il peut retourner un code d'erreur, -1, ainsi que le nombre d'octets lus.
Edit: Dans votre nouveau code, vous devriez vérifier que la valeur de retour de recv () >= 0, non pas qu'il n'est pas -1. Vous devriez alse briser si elle renvoie zéro.
Le code dans edit3 semble raisonnable. Je soupçonne que vous avez probablement écrasa sur la mémoire quelque part d'autre et récoltent le problème à ce point dans votre application.
Avez-vous des limites de dames, purifier, etc que vous pouvez exécuter pour vérifier les dépassements de mémoire tampon, à l'aide d'un libre avais bloc de mémoire etc.
Êtes-vous sûr que vous n'avez pas endommagé le tas ailleurs, avant d'arriver à cette fonction? Essayez de lancer votre programme sous valgrind.
Si votre "EDIT3" version du code est toujours en panne, alors le problème se situe ailleurs dans votre code. Si vous avez fait une erreur dans une autre partie de votre programme (par exemple, en libérant deux fois la même chose, un déréférencement d'un pointeur qui n'a pas de pointage où vous avez pensé il était), alors la résultante de la corruption peuvent passer inaperçus jusqu'à ce que plus tard (comme lorsque vous atteignez la fonction fclose()).
Serait-ce parce que vous êtes à l'écriture de plusieurs octets dans le fichier de taille_fichier ? À l'aide de la logique actuelle si vous avez taille_fichier comme 1025 alors vous allez vous retrouver dans l'écriture de 2048 octets dans le fichier. Je crois, vous devez recalculer le reading_unit à l'intérieur de la boucle while.
Je suis pas sûr de la façon dont le compilateur va interpréter ces deux lignes
Vous utilisez une variable de la taille de la mémoire tampon, plutôt qu'une constante. Je ne suis pas sûr de savoir si cela va se comporter comme vous le souhaitez. Pourriez-vous essayer ce qui suit.