2012-03-16 104 views
1

我一直在调试一个遗留代码,运行在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; 

我们初始化函数列,把它们放在一个变量“列”

/* 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; 
} 

现在,还有另外一个功能,构建整个 “CFG”/配置结构,包含这些ID。 上面的代码:cfg.sen_list [i] - > data_list [j] - > id;其中cfg是一个结构体,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" 

但我得到上面的错误消息(或SIGABRT没有MALLOC_CHECK_)。 我完全不明白这一点。我必须释放这个指针数组,否则它会变成内存泄漏。之前没有其他的免费电话,我可以找到。我不知道为什么csv.data_column_list被认为是无效指针。 Valgrind是不幸的是没有availiable上支持ARM v5TE :(

已经调试这几个小时,并乐意的任何帮助 非常感谢你, 干杯, 本

更新:

我想知道它是否可以连接到一些“范围”问题。在另一个应用程序中有几乎相同的代码,它的工作原理是崩溃的函数“csv_free”被两个程序使用(静态链接)。唯一的区别是,包含要释放的指针的结构通常在工作程序中声明和定义,并声明为external并在除main.c之外的其他文件中定义。 在main.c工作中手动调用“free” “csv_free”崩溃。谜语我这个......

+3

您是否尝试用valgrind运行它? – 2012-03-16 15:23:13

+1

如果你在mallocs之后,并且在释放之前断点,那么所有的指针值是否匹配? – 2012-03-16 15:43:51

+0

你应该检查'csv'是'NULL'还是不在'csv_free'中,并且释放'csv'后将它赋值为NULL。当'csv'为NULL或一些垃圾时,这将保护你免于'csv-> member'。 – phoxis 2012-03-16 15:57:37

回答

0

纵观我的我看到这个老问题。我无法真正确认,因为我不再在该公司工作,但考虑到其他问题,我认为wildplasser是对的。

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

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

0

9出10次,当我遇到的free()错误的问题实际上在分配或初始化开始,让我们验证一下:

  1. 你在哪里实际分配columnscsv.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);