2012-03-16 109 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);