2009-05-15 37 views
2

それはfcloseを達したときに、この関数は例外をスローし、なぜ私は理解して助けてください:このC関数がfcloseでクラッシュするのはなぜですか?

のEclipse CDTは、次のエラーで存在


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); 
    } 
} 

Single stepping until exit from function __kernel_vsyscall, 
which has no line number information.

この機能の目的はを通じてファイルを受信しますソケット。

編集:私はCentOS 5.3を使用しています。つまり、ファイルが作成され、書き込まれます。 MD5でも正しいです。なぜそれがfcloseで失敗しているのか分かりません。

EDIT2:ここで私は得ることができたスタックトレースです:

 
*** glibc detected *** /home/linuser/workspace/proj/Debug/proj: free(): invalid next size (normal): 0x096a0068 *** 
======= Backtrace: ========= 
/lib/libc.so.6[0x4fb0f1] 
/lib/libc.so.6(cfree+0x90)[0x4febc0] 
/lib/libc.so.6(fclose+0x136)[0x4e9c56] 
/home/linuser/workspace/proj/Debug/proj[0x8048cd8] 
/home/linuser/workspace/proj/Debug/proj[0x80492d6] 
/home/linuser/workspace/proj/Debug/proj[0x804963d] 
/lib/libc.so.6(__libc_start_main+0xdc)[0x4a7e8c] 
/home/linuser/workspace/proj/Debug/proj[0x8048901] 
======= Memory map: ======== 
001ff000-00200000 r-xp 001ff000 00:00 0   [vdso] 
0046f000-00489000 r-xp 00000000 08:06 1280361 /lib/ld-2.5.so 
00489000-0048a000 r-xp 00019000 08:06 1280361 /lib/ld-2.5.so 
0048a000-0048b000 rwxp 0001a000 08:06 1280361 /lib/ld-2.5.so 
00492000-005d0000 r-xp 00000000 08:06 1280362 /lib/libc-2.5.so 
005d0000-005d2000 r-xp 0013e000 08:06 1280362 /lib/libc-2.5.so 
005d2000-005d3000 rwxp 00140000 08:06 1280362 /lib/libc-2.5.so 
005d3000-005d6000 rwxp 005d3000 00:00 0 
005d8000-005fd000 r-xp 00000000 08:06 1280369 /lib/libm-2.5.so 
005fd000-005fe000 r-xp 00024000 08:06 1280369 /lib/libm-2.5.so 
005fe000-005ff000 rwxp 00025000 08:06 1280369 /lib/libm-2.5.so 
009b2000-009bd000 r-xp 00000000 08:06 1280372 /lib/libgcc_s-4.1.2-20080825.so.1 
009bd000-009be000 rwxp 0000a000 08:06 1280372 /lib/libgcc_s-4.1.2-20080825.so.1 
009c5000-00aa5000 r-xp 00000000 08:06 5465873 /usr/lib/libstdc++.so.6.0.8 
00aa5000-00aa9000 r-xp 000df000 08:06 5465873 /usr/lib/libstdc++.so.6.0.8 
00aa9000-00aaa000 rwxp 000e3000 08:06 5465873 /usr/lib/libstdc++.so.6.0.8 
00aaa000-00ab0000 rwxp 00aaa000 00:00 0 
08048000-0804a000 r-xp 00000000 08:06 4884214 /home/linuser/workspace/proj/Debug/proj 
0804a000-0804b000 rw-p 00001000 08:06 4884214 /home/linuser/workspace/proj/Debug/proj 
096a0000-096c1000 rw-p 096a0000 00:00 0   [heap] 
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   [stack] 

、ここでは、関数の "更新" 版である:


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); 
    } 
} 

は多分これはクリーナーですか?しかし、私はまだ同じfclose例外を受け取ります。

EDIT3: 私はすべてをコメントアウトし、私は悲しいことに、まだFCLOSEで例外をスローし、次のコード、左:自分自身についての不確実...


void nrec(int sock,char* path,int size) 
{ 
    FILE *handle = fopen(path,"wb"); 
    if(handle == NULL) 
    { 
     printf ("error opening file"); 
     return; 
    } 
    fclose(handle); 
} 
+0

'extern int errno;'を書き込まないでください。 #include を使用します。 'errno'は変更可能な整数のl値ですが、必ずしもintである必要はありません。マルチスレッドプログラミングでは、通常は#define errno *(errno_func())です。ここで、extern int * errno_func(void); –

+0

save_to(書き込みたいファイルの名前)がガベージではないと判断しましたか?また、どのオペレーティングシステムですか? –

+0

memset()操作は実際には必要ありません。 –

答えて

5
  • fclose()は、ファイルが正常にクローズされた場合は0、そうでない場合はEOFを返します。コードを次のように変更することを検討してください。

    if(fclose(handle)){printf( "エラー終了ファイル");出口(-1); }

  • 誰もが指摘しているように、read()にエラーがないかチェックしてください。

  • の後にfcloseが0(成功)を返し、すべてのread()が成功した場合、問題はおそらく他の場所にあります。多分それはVLAでしょう。バッファコードを静的ファイルまたはmalloc/freeに変更することを検討してください。

  • 発信者が実際には480であるにもかかわらず、ファイルサイズと誤解され、ファイルが500バイトであると主張した場合、コードはソケットを永遠に読み取っていきますか?

+1

私はこのチェックを行う機会がありません。関数はfcloseに達すると爆発します。 – Geo

+0

read_nowを0に設定すると爆発しますか? –

+1

fcloseに入ると爆発する。 fcloseは終了して返るチャンスを得られません。 – Geo

2

このコードは非常に思えるが。不必要な割り当ての多く、memset()呼び出し、複雑なロジック。

読んでみることのできる量に制限はありません。バッファスペースを確保している限り、常に読み取ります。利用可能なデータが少なければ少ないほど入手できます。

エラーを正しく処理しません。 read()が失敗した場合は、-1を返します。この場合、Bad Things(TM)がその場で発生します。

私の助言は、それをきれいにし、I/O関数からの戻り値について考え、それらをよりよくチェックしてから、やり直してください。

Linuxにいる場合は、Valgrindまで実行してクラッシュを追跡するのに役立ちます。

2

具体的にはわかりませんが、read()はエラー時にネガを返すことができますか?

2

read()コールからエラーが表示されているかどうかを確認していません。 read()から-1を取得した場合は、チェックしないでfwrite()に渡します。これは、引数としてsize_tをとります。 intの値がsize_t(またはsize_tとして扱われます)に変換されると、かなり大きな数(32ビットシステムでは4 GB - 1)になります。だから、fwrite()はあなたが命令していない場所から多くのデータを書き込もうとします。

1

read()の戻り値をテストする必要があります。-1などのエラーコードと読み取られたバイト数を返すことがあります。

編集:新しいコードでは、recv()の戻り値が> = 0で、-1ではないことをテストする必要があります。ゼロを返すなら、あなたは休憩を取るべきです。

+0

それは起こらない。私はデバッグモードでコードを実行しました。私は-1を受け取ることはありません。 – Geo

+0

@Geo:まだ起こっていない - 将来起こる可能性があります。不都合な時にすべてのシステムコールが失敗し、失敗すると仮定します。例外:getpid()は失敗しません - 他にもいくつかあります。しかし、定義された失敗を持つread()のような呼び出しは失敗するでしょう。 –

0

file_sizeよりも多くのバイトをファイルに書き込んでいる可能性がありますか? file_sizeが1025の場合、現在のロジックを使用すると、2048バイトがファイルに書き込まれます。私はwhileループの中でreading_unitを再計算するべきだと考えています。

+0

同じことが起こります。 – Geo

0

私は、コンパイラはあなたがサイズのバッファではなく、定数に変数を使用しているこの2行

int SIZE = 1024; 
char buffer[SIZE]; 

をどのように解釈するかわかりませんよ。これがあなたの期待どおりに動作するかどうかはわかりません。代わりに以下を試してみてください。

#define SIZE (1024) 
char buffer[SIZE]; 
+0

コンパイラはそれを受け入れるか(C99モードの場合)、構文エラーとして拒否します。 –

+0

コンパイラはそれを受け入れて「クラッシュ時に」実装するかもしれません。新しい機能、新しい学習の機会。 –

1

edit3のコードは妥当性があります。私はあなたがたぶんどこかのメモリを踏んだり、アプリケーションのこの時点で問題を抱えていると思われます。 free'dメモリ・ブロックを使用して、あなたがバッファオーバーランをチェックするために実行できる

あなたが境界チェッカーを持っていますか、浄化などなど

1

は、あなたがに取得する前に、あなたが他の場所で、ヒープが破損していないよろしいですこの機能は? valgrindの下でプログラムを実行してみてください。

1

"EDIT3"バージョンのコードがまだクラッシュしている場合、問題はコードの他の場所にあります。プログラムの別の部分で間違いを犯した場合(たとえば、何かを2回自由にする、ポインタがどこにあるかを指していなかったポインタを間接参照するなど)、結果の破損は後で表示される可能性がありますfclose())。

関連する問題