2013-09-06 1 views
2

가변 크기의 오디오 패킷을 캡처하고 RTP 헤더를 제거한 다음 오디오 데이터를 각각 20 바이트로 연결하려고합니다. 내 목표는 큐와 같은 것을 만들고 버퍼에 20 바이트를 복사하기 전에 포인터 산술을 사용하여 데이터를 잘라내는 것입니다. 이 문제는 큐에 들어오는 많은 양의 오디오 바이트를 가져올 때 발생합니다 (아마 20 개 이상). 여기 캡처 while 루프, 복사 큐에이고, 턱까지 데이터 : 내가 realloc() 또는 관련된 오류가 계속realloc() 또는 free() 또는 double free 또는 corrupt의 C 관련 문제

void cpy_to_q(unsigned char **qs_ptr, unsigned char **qcur_ptr, unsigned char **qsa_ptr, unsigned char *data, int num_bytes, int tot_bytes) { 
    if(*qs_ptr == NULL) { 
      *qs_ptr = (unsigned char *)malloc(num_bytes*sizeof(unsigned char) + 1); 
      *qcur_ptr = *qs_ptr; 
      *qsa_ptr = *qs_ptr; 
      memcpy(*qs_ptr, data, num_bytes); 
    } else { 
      *qs_ptr = (unsigned char *)realloc(*qs_ptr, tot_bytes*sizeof(unsigned char) + 1); 
      printf("size of q: %d\n", tot_bytes); 
      *qsa_ptr += num_bytes; 
      memcpy(*qsa_ptr, data, num_bytes); 
    } 

}

: 여기

run_flag = TRUE; 
    unsigned char *qs_ptr = NULL; //the very start of the queue 
    unsigned char *qcur_ptr = NULL;  //the start of current audio packet 
    unsigned char *qsa_ptr = NULL; //the start of new incoming audio data 
    unsigned char *tmp_ptr = NULL; //points to the start of next audio packet to send 
    unsigned char audio_buf[20]; 
    unsigned char buf[MAX_PACKET_LEN]; 
    unsigned char *pkt_no_hdr = NULL; 
    int num_audio_bytes; 
    int tot_bytes; 
    int num_in_q; 
    /* listen for voip packets */ 
    /* collection */ 

    /* keeps track of audio bytes, send data when = 20 */ 
    pf=fopen("rtp.dat","w"); 
    while (run_flag==TRUE) { 
      if ((num_bytes = read(fd, buf, MAX_PACKET_LEN)) < 0) { 
        perror("recv"); 
        close(sd); 
        exit(1); 
      } 
      pkt_no_hdr = (unsigned char *)calloc(num_bytes-12, sizeof(unsigned char)); 
      /* remove 12 rtp header bytes */ 
      num_audio_bytes = rem_rtp_hdr(pkt_no_hdr, &buf, num_bytes); 
      print_bytes(pkt_no_hdr, num_bytes-12); 
      printf("num audio bytes: %d\n", num_bytes-12); 
      tot_bytes+=num_audio_bytes; 
      num_in_q+=num_audio_bytes; 
      printf("num_in_q: %d\n", num_in_q); 
      cpy_to_q(&qs_ptr, &qcur_ptr, &qsa_ptr, pkt_no_hdr, num_audio_bytes, tot_bytes); 
      free(pkt_no_hdr); 
      if(num_in_q >= 20) { 
        tmp_ptr = qcur_ptr + 20; 
        memcpy(audio_buf, qcur_ptr, 20); 
        qcur_ptr = tmp_ptr; 
        print_bytes(audio_buf, 20); 
        // add header 
        // send mcast packet 
        num_in_q -= 20; 
      } 
    } 

가 cpy_to_q 기능의를 은 cpy_to_q 함수에서 발생해야합니다.

\*** glibc detected \*** ./voipBridge: free(): invalid next size (fast):  0x000000000213b5b0 \*** 

여기에 문제가 발생하면 Valgrind의이 말씀입니다 :

여기
Thread 1: status = VgTs_Runnable 
==3799== at 0x4C2B4F0: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 

==3799== by 0x401211: cpy_to_q (handle_q.c:21) 

==3799== by 0x40177A: rcv_enter code herertp (net_interface.c:142) 

==3799== by 0x401D89: main (voip_bridge.c:48) 

로그 문제 이전에 말씀입니다 : 또한

num audio bytes: 6 n 
num_in_q: 14 
REALLOC 
size of q: 94 
bytes: 0bd2d4b5da0f 
num audio bytes: 6 
num_in_q: 20 
REALLOC 
size of q: 100 
bytes: b15c0f0b86f3b15a0f0bd2d4b5da0f0000000000 
bytes: 08cb24ad9a0f 
num audio bytes: 6 
num_in_q: 6 
REALLOC 
size of q: 106 
bytes: 22c6a0d000e3980ba0f27ccca4336ef243e3168e57150fd6e388b8c7bf 
num audio bytes: 29 
num_in_q: 35 
REALLOC 
size of q: 135 
*** glibc detected *** ./voipBridge: double free or corruption (out): 0x00000000023432f0 *** 

, 나는 큐가 단지 크고 큰지고 유지합니다 알고 있습니다. 전체 블록을 비우지 않고 메모리를 확보 할 수있는 방법이 있습니까?

감사합니다.

+0

C++와 C는 매우 다를 수 있습니다. 이 질문은 실제로 두 가지 모두에 적용됩니까? – crashmstr

+0

아닙니다. 그냥 C입니다.하지만 C++ 지식을 가진 사람도이 질문을 이해할 수 있다고 생각했습니다. – jbrew

+2

이 문제를 [최소 완료 예] (http://sscce.org/)로 줄일 수 있습니까? – Beta

답변

3

이것은 중요한 문제이다

void cpy_to_q(unsigned char **qs_ptr, unsigned char **qcur_ptr, unsigned char **qsa_ptr, 

    unsigned char *data, int num_bytes, int tot_bytes) { 
     if(*qs_ptr == NULL) { 
       *qs_ptr = (unsigned char *)malloc(num_bytes*sizeof(unsigned char) + 1); 
       *qcur_ptr = *qs_ptr; 
       *qsa_ptr = *qs_ptr; 
       memcpy(*qs_ptr, data, num_bytes); 
     } else { 
       // HERE YOU REALLOC THE BASE PTR, BUT DON"T REPOS THE CUR PTR 
       *qs_ptr = (unsigned char *)realloc(*qs_ptr, tot_bytes*sizeof(unsigned char) + 1); 
       printf("size of q: %d\n", tot_bytes); 
       *qsa_ptr += num_bytes; 
       memcpy(*qsa_ptr, data, num_bytes); 
     } 
    } 

할당 마침내 새로운 전체 페이지 ALLOC을 보증 할만큼 중요하게

realloc()가 작동하지만 지금은 현재의 포인터는 여전히 오래된 큐를 가리키는 있습니다 더 이상 존재하지 않습니다.

는,이 문제를 해결 tmp를 크기 VAR의 현재 큐에서 델타를 유지하기 위해, 다음과 realloc 후 새로운 큐베이스에서 새로운 cur_ptr을 기반으로. sa ptr, btw에는 동일한 하우스 키핑 논리가 필요합니다.

이 같은 일, 이것은 성장과 완전히 분리 reset() 또는 shrink() 메커니즘이 항상 목록을 가정합니다.

void cpy_to_q 
(
    unsigned char **qs_ptr, 
    unsigned char **qcur_ptr, 
    unsigned char **qsa_ptr, 
    unsigned char *data, 
    int num_bytes, 
    int tot_bytes 
) 
{ 
    if(*qs_ptr == NULL) 
    { 
     *qs_ptr = malloc(num_bytes*sizeof(unsigned char) + 1); 
     *qcur_ptr = *qs_ptr; 
     *qsa_ptr = *qs_ptr; 
     memcpy(*qs_ptr, data, num_bytes); 
    } 
    else 
    { 
     size_t cur_diff = *qcur_ptr - *qs_ptr; 
     size_t sa_diff = *qsa_ptr - *qs_ptr; 

     // now realloc (note: you really should error check this) 
     *qs_ptr = realloc(*qs_ptr, tot_bytes*sizeof(unsigned char) + 1); 
     printf("size of q: %d\n", tot_bytes); 

     // now reposition your old pointers. 
     *qcur_ptr = *qs_ptr + cur_diff; 
     *qsa_ptr = *qs_ptr + sa_diff; 

     // and finally continue as before 
     *qsa_ptr += num_bytes; 
     memcpy(*qsa_ptr, data, num_bytes); 
    } 
} 
+0

할당 크기가 너무 커지면 realloc이 qs_ptr을 완전히 새로운 위치로 옮길 것입니까? – jbrew

+1

@jbrew 크고 작으며 전혀 다르지 않습니다. 그게 정확히 할 수있는 일이야. ** 모든것 ** 또한 realloc이 완료 될 때 새로운 버퍼로 재구성되어야합니다. 그렇지 않으면 정의되지 않은 동작이 있습니다. 운이 좋았던 것만으로도 모든 관리 지침을 통과하게되었습니다. 그것은 조정을 상당히 공정하게해야합니다 (주의 : 위의 샘플은 코드의 'else'블록입니다. 이해해 주시기 바랍니다). – WhozCraig

+0

오, 그때 당신이 말하는 것을 봅니다. 나는 변화를 만들었고 나는 여전히 얻는다 : *** glibc가 탐지되었다 ***./ voipBridge : 무료() : 다음 크기가 유효하지 않음 (빠름) : 0x0000000001314490 ***. 29 오디오 바이트를 얻었을 때 39가 발생했습니다. 그 전에는 정상적으로 작동합니다. – jbrew

관련 문제