0

最初の反復でクラッシュするソケットから文字列データを受信するコードがあります。

int size_data = 1024*sizeof(char);              
char *data = malloc(size_data);
char *data_aux;
int br_aux=0;
int *nptr;

memset(&data[0], 0, size_data);
int br = recv(sockdata, data, size_data, 0);
data_aux = malloc(br);
while (br>0) {
  br_aux = br_aux + br;
  strcat(data_aux, data);
  br = recv(sockdata,data, size_data, 0);
  if (br > 0) {
    nptr = (int *) realloc(data_aux, br+br_aux);
  }
}
free(data);
printf("%s", data_aux);
free(data_aux);

それほど複雑なことはありませんが、エラーが発生します。

*glibcが検出されました./clientFTP:free():無効な次のサイズ(通常):0x00000000061d6420 * * =======バックトレース:========= /lib64/libc.so.6[0x366be7247f] / lib64 / libc.so.6(cfree + 0x4b)[0x366be728db] ./clientFTP[0x401e39] /lib64/libc.so.6(__libc_start_main+0xf4)[0x366be1d9b4]./clientFTP[0x400b89]=======メモリマップ:======== 00400000-00403000 r-xp 00000000 fd:00 5396214 / home / alumno / FTP / clientFTP 00602000-00603000 rw-p 00002000 fd:00 5396214
/ home / alumno / FTP / clientFTP 061d6000-061f7000 rw-p 061d6000 00
:000[ヒープ]366ba00000-366ba1c000r-xp 00000000 fd:00 1994999
/lib64/ld-2.5.so 366bc1c000-366bc1d000 r--p 0001c000 fd:00 1994999
/lib64/ld-2.5.so 366bc1d000-366bc1e000 rw-p 0001d000 fd:00 1994999
/lib64/ld-2.5.so 366be00000-366bf4e000 r-xp 00000000 fd:00 1995001
/lib64/libc-2.5.so 366bf4e000-366c14e000 --- p 0014e000 fd:00 1995001
/lib64/libc-2.5.so 366c14e000-366c152000 r--p 0014e000 fd:00 1995001
/lib64/libc-2.5.so 366c152000-366c153000 rw-p 00152000 fd:00 1995001
/lib64/libc-2.5.so 366c153000-366c158000 rw-p 366c153000 00:00 0 3672200000-367220d000 r-xp 00000000 fd:00 1995011
/lib64/libgcc_s-4.1.2-20080825.so.1 367220d000-367240d000 --- p 0000d000 fd:00 1995011
/lib64/libgcc_s-4.1.2-20080825.so.1 367240d000- 367240e000 rw-p 0000d000 fd:00 1995011
/lib64/libgcc_s-4.1.2-20080825.so.1 2b5cdf8d9000-2b5cdf8dd000 rw-p 2b5cdf8d9000 00:00 0 2b5cdf8f6000-2b5cdf8f7000 rw-p 2b5cdf8f6000 00:00 0 7fffae47e000-7fffae493000 rw-
p 7fffae5fc000-7fffae600000 r-xp 7fffae5fc000 00:00 0
[vdso] ffffffffff600000-ffffffffffe00000 --- p 00000000 00
:000[vsyscall]中止

4

5 に答える 5

2

2つの異なる問題があります。

まず、ライン

nptr = (int *)realloc(data_aux,(br+br_aux));

3つのことを行います:

  1. br + br_auxバイトを割り当てようとします。
  2. data_auxを指すメモリを解放する場合があります。
  3. nptr新しく割り当てられたメモリのアドレスを指します。

ただし、コードは引き続きdata_aux新しいメモリを指しているかのように使用します。

次に、recv()受信したバイト数を返すため、その情報を使用してデータをバッファに追加する必要があります。

while (br > 0) {
  memcpy(data_aux + br_aux, data, br);
  br_aux += br;
  br = recv(sockdata, data, size_data, 0);
  if (br > 0) {
    nptr = (int *) realloc(data_aux, br + br_aux);
    if (nptr == NULL) {
      // ERROR
    }
    data_aux = nptr;
  }
}

(のような)recv()文字列操作のいずれかと組み合わせた場合の問題は、バイナリデータを返す可能性があることです。そのデータにたまたまゼロバイトが含まれている場合、文字列関数はそれがデータの終わりであると想定し、予期しない、または望まない方法で動作します。strcat()recv()

実際には3番目の問題があります。それは、どの戻り値にもエラーがチェックされないことです。 メモリが有効である、またはsocked通信が成功したと想定するのではなく、常にエラーをチェックしてください。

于 2012-05-16T01:59:10.107 に答える
1

コードには多くの問題がありますが、大きな問題に取り組みます。

  1. メモリを割り当てて、使用する準備ができていると想定しています。

    data_aux = malloc(br);
    ...
    strcat(data_aux, data); /* <- who said data_aux isn't garbage? */
    
  2. reallocデータを移動した場合、または呼び出し自体が失敗してdata_aux十分な大きさではない場合を検討する必要があります。

    サイズが0に等しくない状態で正常に完了するとrealloc()、(移動された可能性のある)割り当てられたスペースへのポインターを返します。サイズが0の場合、正常に渡すことができるnullポインターまたは一意のポインターのいずれかfree()が返されます。使用可能なメモリが十分にない場合realloc()は、nullポインタを返し、に設定errnoENOMEMます。

    data_aux = realloc(data_aux, br + br_aux); /* reassign data_aux */
    
  3. 戻り値をチェックしていません。recv()大きなものは、メモリを割り当てる前に結果をチェックしていません。

    br = recv(...);
    ...
    data_aux = malloc(br); /* -1 as a size is large in unsigned speak */
    
  4. を含まない可能性charのあるデータに対してASCIIZ文字列関数を使用しています。またはmemcpyの代わりに使用します。strcatstrncat

于 2012-05-16T01:55:31.117 に答える
0

ええと、ソケットから受け取った文字列はnullで終了しますか?

提案:

  1. メッセージを送信する前に、メッセージにnullバイトが含まれていることを確認してください

  2. strncat()を使用する

  3. 必要に応じて、バッファを自分でヌル終了します

PS:「strcat(data_aux)」のバッファをオーバーランしていると思います。これにより、「data」と「data_aux」の両方が誤って破損しています。

于 2012-05-16T01:47:05.473 に答える
0

成功するとrealloc()、入力メモリブロックは無効になり、返されたポインタは新しいメモリブロックを指しています。失敗した場合realloc()でも、入力メモリブロックは有効です。返されたポインタを、nptr何にも使用されていないdata_aux変数に割り当てており、再割り当てされたメモリを指すように変数を更新することはありません。free()freedata_auxに呼び出すとき、realloc()事前に呼び出されて成功した場合は、間違ったポインターを解放することになり、見ているようにクラッシュする可能性があります。

これを変える:

nptr = (int *) realloc(data_aux,(br+br_aux)); 

代わりにこれに:

nptr = (char*)realloc(data_aux, br_aux + br); 
if (!nptr)
{
    ... error handling ...
    break;
}
data_aux = nptr;

そうは言っても、代わりにロジック全体を次のようなものに書き直す必要があります。recv()ループ内で複数回呼び出す必要はありません。

int size_data = 1024 * sizeof(char);                
char *data_aux = NULL;
int br_aux = 0;  
char *nptr;  

char *data = malloc(size_data);  
if (data)
{
    int br = recv(sockdata, data, size_data, 0);
    while (br > 0)
    {  
        nptr = (char*) realloc(data_aux, br_aux + br);
        if (!nptr)
            break;

        data_aux = nptr;
        memcpy(&data_aux[br_aux], data, br);  
        br_aux = br_aux + br;  
    }  

    free(data);  
}

printf("%.*s", br_aux, data_aux);  
free(data_aux);  

さらに単純化するには、data代わりにバッファをスタックに配置します。

char* data_aux = NULL;
int br_aux = 0;  

char data[1024];
char *nptr;  

int br = recv(sockdata, data, sizeof(data), 0);
while (br > 0)
{  
    nptr = (char*) realloc(data_aux, br_aux + br);
    if (!nptr)
        break;

    data_aux = nptr;
    memcpy(&data_aux[br_aux], data, br);  
    br_aux = br_aux + br;  
}  

printf("%.*s", br_aux, data_aux);  
free(data_aux);  
于 2012-05-16T02:12:24.547 に答える
0
data_aux = malloc(br);   //data_aux may not filled with zero
//data_aux[0] = '\o';

while (br>0)
{
    br_aux = br_aux + br;  
    strcat(data_aux,data); //this may casue overflow, data may not end with '\0'
    br = recv(sockdata,data, size_data,0); 
    if(br>0)
    {
        //need check nptr is NULL? and size is (br + br_aux + 1), '\0' need one byte
        //nptr = (char*)realloc(data_aux,(br + br_aux + 1)); 
        nptr = (int *)realloc(data_aux,(br+br_aux)); 
        // if (nptr != NULL)
        //     data_aux = nptr;
        // else
        //     Error handling
    }
}
于 2012-05-16T02:39:43.030 に答える