【问题标题】:Segmentation fault with queue algorithm队列算法的分段错误
【发布时间】:2011-10-18 20:15:58
【问题描述】:

我做了一个如下所示的小队列,用于存储二进制数据。 queue_read() 和 queue_del() 在队列的一侧工作,执行读取和删除操作。 queue_add() 将数据添加到队列的另一端。当我在另一个代码中使用此代码来存储数据时,我遇到了分段错误问题。但即使使用 gdb,我也找不到导致分段问题的原因。它大部分时间都像 malloc->memalign 问题,但我找不到任何空指针。单独测试此代码,我找不到任何问题。如果实施有任何问题,如果有人可以指出,那就太好了。谢谢

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct queue_node {
    struct queue_node *next;
    unsigned char data;
};

struct queue {
    struct queue_node *first;
    struct queue_node *last;
};

/* initialize the queue */
void init_queue(struct queue *q) {
    q->first = q->last = NULL;
}

/* check if the queue is empty or not */
int queue_empty_p(const struct queue *q) {
    return q->first == NULL;    
}

/* Reading 'len' bytes data from queue to buffer variable 'value' 
*
*  RETURNS bytes read which can be less than or equal to the requested 
*  value of 'len'
*/
int queue_read(struct queue *q, unsigned char *read_buffer, unsigned int len) {
    unsigned int i;
    struct queue_node *tmp = (struct queue_node *) malloc(
            sizeof(struct queue_node));

    tmp = q->first;
    for (i = 0; i < len; i++) {
        if (tmp == NULL) {
            read_buffer[i] = 0;
            return (i);
        }
        read_buffer[i] = tmp->data;
        tmp = tmp->next;
    }
    return len;
}

/* Deleting specified no of bytes from queue. Usually done after queue_read() */
int queue_del(struct queue *q, unsigned int no_of_bytes) {
    unsigned int i;

    for (i = 0; i < no_of_bytes; i++) {
        if (!q->first) {
            return 1;
        }
        struct queue_node *tmp = q->first;
        if (q->first == q->last)
            q->first = q->last = NULL;
        else
            q->first = q->first->next;

        free(tmp);
    }
    return 0;
}

/* Adding 'len' bytes of data contained in the variable 'value' to the queue */
int queue_add(struct queue *q, unsigned char *value, unsigned int len) {

    struct queue_node *node;
    unsigned int i;

    for (i = 0; i < len; i++) {
        node = (struct queue_node *) malloc(sizeof(struct queue_node));
        if (node == NULL) {
            return 1;
        }
        node->data = *(value + i);
        if (q->first == NULL)
            q->first = q->last = node;
        else {
            q->last->next = node;
            q->last = node;
        }
        node->next = NULL;
    }
    return 0;
}

int main() {
    struct queue left_queue;
    char *buffer = (char *)malloc(100);
    int read_bytes;

    strcpy(buffer, "This is a test");
    init_queue(&left_queue);

    queue_add(&left_queue, (unsigned char *) buffer, strlen(buffer));

    queue_del(&left_queue, 3);

    read_bytes = queue_read(&left_queue, (unsigned char *)buffer, 1500);
    buffer[read_bytes]=0;
    printf("Buffer: %s \nBytes read %d \n", (unsigned char *)buffer, read_bytes);

    return 0;
}

编辑:gdb 回溯输出

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb6ef3b70 (LWP 2678)]
0x0012f4df in memalign () from /usr/lib/libefence.so.0
#0  0x0012f4df in memalign () from /usr/lib/libefence.so.0
#1  0x0012f88b in malloc () from /usr/lib/libefence.so.0
#2  0x08049576 in queue_add (q=0xb7f21fc8, 
    value=0xb7f2da28 "GET /wiki/Special:Search?search=rohc&sourceid=Mozilla-search HTTP/1.1\r\nHost: en.wikipedia.org\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Fire"..., 
    len=440) at pep_core.h:248
#3  0x0804cc81 in fn_process_tcp () at pep_core.c:584
#4  0x0013b96e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0
#5  0x00228a4e in clone () from /lib/tls/i686/cmov/libc.so.6
#0  0x0012f4df in memalign () from /usr/lib/libefence.so.0
No symbol table info available.
#1  0x0012f88b in malloc () from /usr/lib/libefence.so.0
No symbol table info available.
#2  0x08049576 in queue_add (q=0xb7f21fc8, 
    value=0xb7f2da28 "GET /wiki/Special:Search?search=rohc&sourceid=Mozilla-search HTTP/1.1\r\nHost: en.wikipedia.org\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Fire"..., 
    len=440) at pep_core.h:248
        node = 0xb661bff8
        i = 245
#3  0x0804cc81 in fn_process_tcp () at pep_core.c:584
        ip_queue_table = 0xb7f2d9fc
        tmp_ip_queue_table = 0x0
        tcp_conn = 0xb7f21fa8
        tmp_tcp_conn = 0x0
        tcphdrs = 0xb7f2da14
        iphdrs = 0xb7f2da00
        packet_data = 0xb7f2da28 "GET /wiki/Special:Search?search=rohc&sourceid=Mozilla-search HTTP/1.1\r\nHost: en.wikipedia.org\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Fire"...
        read_buffer = 0xb7f17a24 ""
        read_bytes = 0
        payload_size = 440
        ret = 0
        rawfd = 9
        one = 1
#4  0x0013b96e in start_thread () from /lib/tls/i686/cmov/libpthread.so.0
No symbol table info available.
#5  0x00228a4e in clone () from /lib/tls/i686/cmov/libc.so.6
No symbol table info available.

valgrind 的输出

我按照你的建议运行了 valgrind 并得到了以下结果

Syscall param socketcall.sendto(msg) points to uninitialised byte(s)

上述错误出现 4 次,然后出现以下消息

==3159== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==3159==  Bad permissions for mapped region at address 0x5AD2FFC
==3159==    at 0x804962F: queue_read (pep_core.h:279)
==3159==    by 0x804D672: fn_thread_pep_left_sctp_client (pep_core.c:856)
==3159==    by 0x403D96D: start_thread (pthread_create.c:300)
==3159==    by 0x412AA4D: clone (clone.S:130)

【问题讨论】:

  • 段错误不一定是由 NULL 指针引起的。您说您使用了 gdb,您能否提供段错误后的回溯?
  • 你确定问题不是你的第二个程序吗?我的猜测是您将错误的长度传递给queue_read,它会覆盖某些内容。正如您在示例中所做的那样。
  • 你试过用 valgrind 测试它吗?如果是这样,你能给出 valgrind 的输出吗?
  • 不是段错误的原因,但您在queue_read 中存在内存泄漏:您将新分配的queue_node 分配给tmp,并立即将tmp 设置为q-&gt;first .你不需要那个malloc
  • 感谢所有 cmets krynr 我已将回溯添加到问题中。希望够了。 Banthar queue_read() 用于返回可以从队列中读取的字节数,即可以小于或等于传递的长度。 tune2fs 不,我目前正在尝试 valgrind .... eran 好的,我将删除 malloc ...... Chad 抱歉删除了 C++标签

标签: c queue


【解决方案1】:

不确定我是否理解您的代码,但似乎queue_read 的工作原理与read 基本相似,即读入传入的缓冲区。

char *buffer = (char *)malloc(100);
[...]
read_bytes = queue_read(&left_queue, (unsigned char *)buffer, 1500);

您是否只是将太多数据读入太小的缓冲区?

【讨论】:

  • 感谢您的意见。抱歉,我刚刚为示例给出了 100 和 1500 的混淆。在实际情况下,它总是 1000 字节。 queue_read() 可以复制小于或等于传递给它的长度值的字节。请参阅下面的tmp = q-&gt;first; for (i = 0; i &lt; len; i++) { if (tmp == NULL) { read_buffer[i] = 0; return (i); } read_buffer[i] = tmp-&gt;data; tmp = tmp-&gt;next; } return len; ,因此代码将检查队列是否为空,它将返回它读取的数量。
【解决方案2】:
struct queue_node *tmp = (struct queue_node *) malloc(
        sizeof(struct queue_node));

tmp = q->first;

我认为这是问题所在,发生的情况是您在特定地址分配了一块内存,但是您没有使用该内存,而是将指针设置为指向其他东西。因此出现内存泄漏。请记住,当您将这样的值分配给指针时,您不会复制值,而是您的指针现在指向内存中的另一个位置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    相关资源
    最近更新 更多