realloc()或free()或double-free中的C出现问题或损坏
我试图捕获大小可变的音频数据包,去掉RTP报头,然后将音频数据连接到每个20字节。我的目标是创建一个类似队列的东西,在将20个字节复制到缓冲区之前,只需使用指针算法来分割数据。当大量音频字节进入队列(可能大于20)时,就会出现问题。下面是一个while循环,用于捕获、复制到队列并切碎数据:realloc()或free()或double-free中的C出现问题或损坏,c,C,我试图捕获大小可变的音频数据包,去掉RTP报头,然后将音频数据连接到每个20字节。我的目标是创建一个类似队列的东西,在将20个字节复制到缓冲区之前,只需使用指针算法来分割数据。当大量音频字节进入队列(可能大于20)时,就会出现问题。下面是一个while循环,用于捕获、复制到队列并切碎数据: run_flag = TRUE; unsigned char *qs_ptr = NULL; //the very start of the queue unsigned char *
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;
}
}
}
我不断收到与realloc()
或free()
相关的错误,这些错误必须发生在cpy\u to\u 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);
}
\*** 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 ***
而且,我意识到队列会越来越大。有没有一种方法可以在不释放整个块的情况下释放内存
谢谢。这是一个重大问题:
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大小变量中,然后将新cur_ptr置于realloc之后的新队列基础之上。顺便说一句,sa ptr需要相同的内务管理逻辑
类似这样的东西,请注意,这假设您的列表一直在增长,并且有一个完全独立的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);
}
}
C++和C可以有很大的不同。这个问题真的适用于两者吗?不适用。只是C。但是我想有C++知识的人也可以理解这个问题。你有没有可能把它减少到A?你是说当分配大小变得太大时,ReLoLc会完全移动QSypTR到一个新的位置?这正是它能做的。当realloc完成时,作为指向当前缓冲区的指针的所有内容都需要重新配置为新缓冲区,否则您将有未定义的行为。你觉得自己很幸运,只是碰巧错过了你所有的管理指针。它应该使调整相当局部(注意:上面的示例是代码中的
else
块,我希望您理解)。哦,我明白您当时的意思了。我做了更改,但仍然得到:**glibc检测到***./voipBridge:free():无效的下一个大小(fast):0x0000000001314490***。它发生在我得到29个音频字节,然后是39个。在这之前它工作得很好。@jbrew那么在您的代码中管理队列指针还有另一个问题,但这仍然很可怕。另请注意,如果有任何数据指针引用此之外的队列数据块,同样,在realloc之后,必须假定这些数据指针无效。对于队列处理逻辑,我必须关注它一段时间。它似乎比以前工作得好得多,所以我假设其他地方也有类似的问题,如您所提到的。这种行为很奇怪,因为有时它会继续,如果我停止并重新启动程序,它会立即失败。谢谢你的帮助,我会接受的。