2

可変サイズのオーディオ パケットをキャプチャし、RTP ヘッダーを取り除き、オーディオ データをそれぞれ 20 バイトに連結しようとしています。私の目標は、キューのようなものを作成し、20 バイトをバッファーにコピーする前にポインター演算を使用してデータを切り刻むことです。この問題は、大量のオーディオ バイトがキューに入ると発生します (おそらく 20 バイトを超える)。データをキャプチャしてキューにコピーし、細かく分割する while ループを次に示します。

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 関数は次のとおりです。

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

}

cpy_to_q 関数に関連する、realloc()またはfree()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 ***

また、キューがますます大きくなり続けることもわかっています。ブロック全体を解放せずにメモリを解放する方法はありますか?

ありがとう。

4

1 に答える 1

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

割り当てが最終的に新しいフルページ割り当てを保証するのに十分なほど大きくなると、realloc()うまくいきますが、現在のポインターはまだ存在していない古いキューを指しています。

これを修正するには、現在のキューからのデルタを tmp サイズ var に保持してから、再割り当て後に新しいqueue-base から新しいcur_ptr をベースにします。ところで、saptr には同じハウスキーピング ロジックが必要です。

したがって、このようなものです。これは、リストが常に成長し、完全に個別のreset()orshrink()メカニズムを持っていることを前提としていることに注意してください。

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);
    }
}
于 2013-09-06T18:31:08.783 に答える