C语言服务端客户端程序出队操作触发Segmentation Fault问题排查
队列出队触发Segmentation Fault问题排查与解决
开发服务端-客户端程序时,客户端collector负责将数据包入队,sender负责出队,但执行出队操作时频繁触发Segmentation Fault错误。
队列实现代码
aqueue *init_aqueue(void) { aqueue *q; q = malloc(sizeof(aqueue)); q->head = NULL; q->tail = NULL; return (q); } aqueue_node *init_node(packet *data, aqueue_node *tail) { aqueue_node *new; new = malloc(sizeof(aqueue_node)); new->data = data; new->prev = tail; new->next = NULL; } packet *peek(aqueue *q) { packet *res; if (!q->size) return (NULL); else { res = malloc(sizeof(packet)); res->length = q->head->data->length; res->payload = strndup(q->head->data->payload, res->length); } return (res); } void enqueue (aqueue *q, packet *data) { aqueue_node *new; new = init_node(data, q->tail); if (q->head == NULL) //adding first node of aqueue { q->head = new; q->size = 1; } else { q->tail->next = new; q->size += 1; } q->tail = new; } packet *dequeue(aqueue *q) { packet *data; aqueue_node *temp; if (q->size == 0) { return (NULL); } else { if (q->head == q->tail) { //When aqueue contains only one node free(q->head->data); free(q->head); q->tail = NULL; q->head = NULL; } else { data = peek(q); temp = q->head; q->head = q->head->next; q->head->prev = NULL; free(temp->data); free(temp); } q->size--; return (data); } }
共享资源与线程代码
队列共享定义(agent.c)
aqueue * queue;
Collector入队代码
//send four packet pthread_mutex_lock(&p->aqueue_lock); enqueue(q, get_mem_info()); enqueue(q, get_net_info()); enqueue(q, get_cpu_info()); enqueue(q, get_proc_info());
Sender出队代码
packet *data; data = NULL; if (q->size > 0) { data = dequeue(q); } if (data) { if (0 > send(clientfd, data->payload, data->length, 0)) { perror("send error"); exit (EXIT_FAILURE); } }
lldb调试结果
* thread #2, name = 'agent', stop reason = signal SIGSEGV: invalid address (fault address: 0x50e8) frame #0: 0x0000aaaaaaaa3c64 agent`dequeue(q=0x0000aaaaaaab62e0) at agent_queue.c:85:18 82 { 83 cur = q->head; 84 q->head = q->head->next; -> 85 q->head->prev = NULL; 86 free(cur->data); 87 free(cur); 88 }
尝试的修改
- 修复
init_node函数,添加返回值:
aqueue_node *init_node(packet *data, aqueue_node *tail) { aqueue_node *new; new = malloc(sizeof(aqueue_node)); new->data = data; new->prev = tail; new->next = NULL; return (new); //added }
修改后错误仍存在。
- 修改
dequeue函数变量名,明确返回复制的数据:
packet *dequeue(aqueue *q) { packet *copied_data; aqueue_node *temp; printf("queue size : %d\n", q->size); if (q->size == 0) { return (NULL); } else { if (q->head == q->tail) { //When aqueue contains only one node free(q->head->data); free(q->head); q->tail = NULL; q->head = NULL; } else { copied_data = peek(q); temp = q->head; q->head = q->head->next; q->head->prev = NULL; free(temp->data); free(temp); } q->size--; return (copied_data); } }
- 修复
enqueue函数中prev指针赋值:
void enqueue (aqueue *q, packet *data) { aqueue_node *new; new = init_node(data, q->tail); if (q->head == NULL) //adding first node of aqueue { q->head = new; q->size = 1; } else { q->tail->next = new; new->prev = q->tail; //added q->size += 1; } q->tail = new; }
最终原因与解决
经过排查,发现问题源于调试阶段添加了释放整个队列的代码,但后续忘记删除,导致出队操作时访问了已经被释放的内存区域,触发Segmentation Fault。移除残留的队列释放代码后,问题解决。
内容的提问来源于stack exchange,提问作者acho
相关产品推荐
相关产品推荐

