free()无效指针 - 释放指针数组失败

时间:2012-03-16 15:22:12

标签: c memory-leaks malloc free

我一直在调试一段遗留代码,在带有linux的XScale(arm v5te)系统上运行,崩溃可重现。

我已经使用gdb调试并将MALLOC_CHECK_设置为1.这是很多代码,所以只是一些片段:

我们有这样的结构:

typedef struct {
...clipped..
    char **data_column_list;
    /** data column count */
    int data_column_cnt;
...clipped
} csv_t;

我们初始化函数中的列,将它们放在变量“columns”

/* Allocating memory for pointer to every register id */
columns = (char **) malloc(column_cnt * sizeof(char *));

column_cnt = 0;
/* loop over all sensors */
for(i=0; i<cfg.sen_cnt; i++) {
    /* loop over all registers */
    for(j=0; j<cfg.sen_list[i]->data_cnt; j++) {
        /* Storing all the pointers to id */
        columns[column_cnt++] = cfg.sen_list[i]->data_list[j]->id;
    }
}

在另一个功能中,会发生什么:

/* free the previous list */
csv_free(lc_csv);

lc_csv->data_column_list = columns;
lc_csv->data_column_cnt = column_cnt;

csv_free正在:

void csv_free(csv_t *csv) {
    if(csv->data_column_cnt > 0)
        free(csv->data_column_list);

    csv->data_column_cnt = 0;
}

现在,还有另一个函数,构建包含这些id的整个“cfg”/ config结构。 上面的代码:cfg.sen_list [i] - &gt; data_list [j] - &gt; id; cfg是一个struct,sen_list是一个指向结构的指针数组,data_list是一个指向其他结构的指针数组,包含一个字符串“id”。

当程序获得信号SIGUSR1时,配置正在更新。所有这些data_list和sen_list结构都被释放,然后生成新的结构。 然后使用第一个函数,生成新的id列并将其放入csv结构中,但之前将释放旧列表。

这就是它崩溃的地方。在csv_free。

*** glibc detected *** /root/elv: free(): invalid pointer: 0x0001ae88 ***

我认为应该是这样的。你有一个指针数组。释放指针时,必须释放指针,指向一组指针(数组)。 或者输入代码术语,上面的情况应该类似于:

char **ar = malloc(n * sizeof(char *));
char *xn = malloc(10 * sizeof(char)); // Do for 0 to n strings
...
ar[n] = xn; // Do for 0 to n strings
...do stuff...
free(xn); // Do for 0 to n strings
free(ar);

当释放包含id字符串的结构时,我的指针数组仍然带有(无效)指针,而不是空指针:

(gdb) p csv
$40 = {sysid = 222, ip = '\0' <repeats 49 times>, 
    module = "elv_v2", '\0' <repeats 14 times>, format_type = 1, msg_id = 0, 
    data_column_list = 0x1ae88, data_column_cnt = 10, pub_int = 30, 
    line_cnt = 0, pub_seq = -1, format = 0x18260}
(gdb) p csv.data_column_list[0]
$41 = 0x1b378 "0"

但是我得到了上面的错误消息(或没有MALLOC_CHECK_的SIGABRT)。 我根本不明白这一点。我必须释放这个指针数组,否则它将成为内存泄漏。在那之前没有其他的免费电话,我能找到。我不知道为什么csv.data_column_list被认为是无效指针。 遗憾的是,Valgrind在v5te手臂上无法使用:(

已经进行了数小时和数小时的调试,并乐意为您提供帮助。 非常感谢你, 干杯, 本

更新:

我想知道它是否可以连接到某个“范围”问题。在另一个应用程序中有几乎相同的代码,它可以工作。崩溃的功能,两个程序使用“csv_free”(静态链接)。唯一的区别是,包含要释放的指针的结构在工作程序中正常声明和定义,并声明为external并在另一个文件中定义而不是main.c 在main.c中手动调用“free”有效,同时调用“csv_free”崩溃。捣我这个...

2 个答案:

答案 0 :(得分:0)

当遇到free()错误时,10次中有9次问题实际上是在分配或初始化时启动的,所以让我们稍微验证一下:

  1. 在您致电columns 之前,您实际将csv.data_columns_list分配给csv_free 的位置?如果你在free()时没有初始化,那就可以解释错误。

  2. 在第二个代码块中,如果是初始column_cnt(我猜是设置的) 其他地方?)小于你要写在外面的循环之后的column_cnt 阵列。人们希望MALLOC_CHECK_能够捕捉到这一点,但如果你断言,会发生什么 如下:

    /* Allocating memory for pointer to every register id */
    columns = (char **) malloc(column_cnt * sizeof(char *));
    
    int old_column_cnt = column_cnt;
    column_cnt = 0;
    /* loop over all sensors */
    for(i=0; i<cfg.sen_cnt; i++) {
        /* loop over all registers */
        for(j=0; j<cfg.sen_list[i]->data_cnt; j++) {
            /* Storing all the pointers to id */
            columns[column_cnt++] = cfg.sen_list[i]->data_list[j]->id;
        }
    }
    assert(old_column_cnt >= column_cnt);
    

答案 1 :(得分:0)

回顾我过去的问题,我看到了这一点。我无法真正验证,因为我不再在该公司工作,但想到我们遇到的其他问题,我认为wildplasser是对的。

从信号处理程序中调用任何大型函数是个坏主意。特别是如果你没有检查你所做的一切是否是可重入的。它是遗留代码,所以至少它不完全是我的错;)

现在我会在信号处理程序中设置一个标志,并在设置该标志时(或类似的东西)调用我的主循环中的例程。