free () неверный указатель - сбой массива указателей - PullRequest
1 голос
/ 16 марта 2012

Я отлаживал часть унаследованного кода, работающего в системе XScale (arm v5te) с linux, который воспроизводит сбои.

Я отладил с помощью 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;
}

Теперь есть еще одна функция, создающая всю структуру "cfg" / config, котораясодержит эти идентификаторы.Код выше: cfg.sen_list [i] -> data_list [j] -> id;где cfg - это структура, sen_list - это массив указателей на структуры, data_list - это массив указателей на другие структуры, которые содержат строку «id».

Когда программа получает сигнал SIGUSR1, конфигурацияобновляется.Все эти структуры data_list и sen_list освобождаются, затем генерируются новые.Затем с первой функцией генерируются новые столбцы идентификаторов и помещаются в структуру 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);

Когда структуры, содержащие строки идентификаторов, освобождаются, у меня все еще есть массивы указателей с (недействительными) указателями, а не с нулевыми указателями:

(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, к сожалению, недоступен на arm v5te: (

Отлаживаю это часами и буду рада за любую помощь. Большое спасибо, Cheers, Бен

ОБНОВЛЕНИЕ:

Мне интересно, может ли это быть связано с какой-то проблемой "области видимости". В другом приложении работает практически идентичный код. Сбой функции "csv_free" используется обеими программами (статически связанными).Единственное отличие состоит в том, что структура, содержащая указатель для освобождения, объявляется и обычно определяется в рабочей программе и объявляется как external и определяется в другом файле, отличном от main.c. Вызов «free» вручную в main.c работает, в то время как работаетвызов "csv_free" дает сбой. Загадкой мне это ...

Ответы [ 2 ]

0 голосов
/ 28 февраля 2014

Просматривая мои старые вопросы, я видел это. Я не могу проверить, так как я больше не работаю в этой компании, но думая о других проблемах, которые у нас были, я думаю, что wildplasser был прав.

Вызов любых больших функций из обработчиков сигналов - плохая идея. Особенно, если вы еще не проверили, является ли все, что вы делаете, реентерабельным. Это был устаревший код, так что, по крайней мере, это не моя вина;)

В настоящее время я бы устанавливал флаг в обработчике сигналов и вызывал подпрограмму в моем основном цикле, когда этот флаг установлен (или что-то в этом роде).

0 голосов
/ 12 апреля 2012

9 из 10 раз, когда я сталкиваюсь с ошибками free (), проблема фактически началась при выделении или инициализации, поэтому давайте проверим это немного:

  1. Где вы фактически назначаетеcolumns до csv.data_columns_list до вы звоните csv_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);
    
...