invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 12:10
Оценка: :)
Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.

В общем случае MAPPER это структура котороая имеет следующий вид:


typedef struct
        {
                int colls_num; //number of MAPPING strings
                char **name;  //number of substrings
                char **value;      //substring values array
        }MAPPER;


То есть в заполненном виде вывод структуры может иметь вид:


colls_num: 2

name: name1 value: value1
name: name2 value: value2


Заполнение данной структуры происходит через специальный метод. который так же реализован чрез структуру SPLITTER, но это не суть важно. Метод проверен, отрабатывает верно и чисто. Для ясности приведу пример SPLITTER структуры



typedef struct
        {
                int colls_num;  //number of substrings
                char **substrings;      //substring values array
        }SPLITTER;




Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):





MAPPER MAP_string(SPLITTER *arr)
{
        MAPPER map;

        int i=0;

        int k=0;

        for (i=1;i<=arr->colls_num;i++)
        {
                //int j=0;

                //while (arr->substrings[i-1][j]!='\0') j++;
                int j=strlen(arr->substrings[i-1]);

                if ((i+1)%2 == 0)
                {

                        if (i==1)

                                map.name=(char **)malloc(sizeof(char *)*j+1);

                        else

                                map.name=(char **)realloc(map.name,sizeof(char*)*j+1);

                        printf("i='%u'\n",i);
                        printf("k='%u'\n",k);
                        map.name[k]=arr->substrings[i-1];
                        printf("name %u %s\n",k,map.name[k]);

                }
                else

                {
                        if (i==2)

                                map.value=(char **)malloc(sizeof(char *)*j+1);

                        else

                                map.value=(char **)realloc(map.value,sizeof(char*)*j+1);

                        printf("i='%u'\n",i);
                        printf("k='%u'\n",k);
                        map.value[k]=arr->substrings[i-1];
                        printf("value %u %s\n",k,map.value[k]);


                        k++;

                }
        }

map.colls_num=k++;
printf("%u\n",arr->colls_num);
printf("%u\n",map.colls_num);
printf("%s\n",map.value[0]);


return map;

}


Так вот. Суть в том, что при формировании структуры MAPPER на этапе формирования последнего value (то есть если всего у нас 4 элемента ИМЯ/ЗНАЧЕНИЕ ) возникает ошибка invalid fastbin entry (free): 0x0000000000c350f0 ***


То есть имя для 4 элемента формируется а значение нет.

Косяк где то вот тут:


else

                {
                        if (i==2)

                                map.value=(char **)malloc(sizeof(char *)*j+1);

                        else

                                map.value=(char **)realloc(map.value,sizeof(char*)*j+1);


Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.
На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка (только пути к файлам исходников обработчиков поправьте, чтобы собралось). Буду благодарен за наводку.
Re: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 12:28
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.


1. Зачем C?
2. Для C есть GLib.
Re[2]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 12:31
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


O>>Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.


EP>1. Зачем C?

EP>2. Для C есть GLib.

Хочется поизобретать велосипед это раз и Я не знал что есть GLib это два)
Re[2]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 12:41
Оценка:
Тем не менее ответ на вопрос очень хочется узнать)
Re: invalid fastbin entry (free):
От: watchmaker  
Дата: 17.04.14 13:04
Оценка: +1
Здравствуйте, Ovoshlook, Вы писали:


O>Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.

Проблема в том, что ты записываешь свои данные в область памяти, которую ты не выделял. Ну а вскрывается это не сразу, а собственно при других операциях с памятью, вроде того же вызова realloc.

Вообще, код ужасен.
Попробуй для начала его разбить на функции, убрать копипасту, дать переменным нормальные имена, а не безликие i/j/k.
Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?



O>На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка

Молодец. Пусть там и лежат. Больше их не трогай, а возьми GLib :)
Re[2]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 18:16
Оценка:
Здравствуйте, watchmaker, Вы писали:

O>Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.

Проблема в том, что ты записываешь свои данные в область памяти, которую ты не выделял. Ну а вскрывается это не сразу, а собственно при других операциях с памятью, вроде того же вызова realloc.

Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки? Если не сложно- можно более подробно? пока что не понятно где я с выделением памяти просчитался?

Вот здесь:
else

                {
                        if (i==2)

                                map.value=(char **)malloc(sizeof(char *)*j+1);

                        else

                                map.value=(char **)realloc(map.value,sizeof(char*)*j+1);

Если я встречаю первое значение для value я выделяю память через valloc для элемента массива, если же у меня знчение отличное от первого, значит я могу утверждать что память уже выделена и остается только ее расширить на необходимое количество байт.

Не понимаю пока что что не так в этом куске?

W>Попробуй для начала его разбить на функции, убрать копипасту, дать переменным нормальные имена, а не безликие i/j/k.

Ок. Принято

W>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?


Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j

O>>На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка

W>Молодец. Пусть там и лежат. Больше их не трогай, а возьми GLib

GLib не тяжеловата для таких, в общем то не сильно затратных операций? Может есть аналоги поменьше?
Re[3]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 18:22
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

W>>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?

O>Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j

map.name — это массив массивов, или по-другому — массив строк.
Количество элементов в массиве строк, зависит от количества строк, и не зависит от размера конкретной строки (то есть не зависит от j).
Re[4]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 19:47
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


W>>>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?

O>>Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j

EP>map.name — это массив массивов, или по-другому — массив строк.

EP>Количество элементов в массиве строк, зависит от количества строк, и не зависит от размера конкретной строки (то есть не зависит от j).

map.name=(char **)malloc(sizeof(char *)*j+1);

Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
Re[5]: invalid fastbin entry (free):
От: watchmaker  
Дата: 17.04.14 19:54
Оценка: +1
Здравствуйте, Ovoshlook, Вы писали:


O>map.name=(char **)malloc(sizeof(char *)*j+1);

O>Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
Хорошо, допустим ты так выделяешь память для конкретной строки. Тогда объясни, почему ты решил умножить j на sizeof(char*)? И почему у тебя тип результата является не указателем на строку, а указателем на массив указателей? И почему ты вообще присваиваешь результат переменной map.name?

O>Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки?

Такая ошибка называется buffer overflow. Ну то есть она бы так называлась, если бы в твоей программы был смысл :) На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.
Re[6]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 20:15
Оценка:
Здравствуйте, watchmaker, Вы писали:


O>>Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.

W>Хорошо, допустим ты так выделяешь память для конкретной строки. Тогда объясни, почему ты решил умножить j на sizeof(char*)? И почему у тебя тип результата является не указателем на строку, а указателем на массив указателей? И почему ты вообще присваиваешь результат переменной map.name?

j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)

Так как переменная map.name массив массивов, то получается что делая realloc я добавляю память к массиву массивов, выделяя для элемента массива — строки, необходимое количество байт.

O>>Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки?

W>Такая ошибка называется buffer overflow. Ну то есть она бы так называлась, если бы в твоей программы был смысл На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.

покажите конкретно пожалуйста- где у меня путаница с указателями. Я действитльно ее не вижу. я как бы не отрицаю вашей правоты и не убеждаю вас в вашей неправоте, мне просто искренне интересно где я накосячил (если накосячил) с выделением памяти и как оно по хорошему должно быть?
Re[7]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 20:20
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)


Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
Re[8]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 21:22
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


O>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)


EP>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?


Строка состоит из символов
Re[9]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 21:27
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)

EP>>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
O>Строка состоит из символов

char — тип символа
char* — тип указателя на символ
sizeof(T) — возвращает размер типа T
Как посчитать размер строки, состоящей из символов, зная общее количество символов?
Re[10]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 21:34
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


O>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)

EP>>>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
O>>Строка состоит из символов

EP>char — тип символа

EP>char* — тип указателя на символ
EP>sizeof(T) — возвращает размер типа T
EP>Как посчитать размер строки, состоящей из символов, зная общее количество символов?

умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов>
Re[11]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 21:54
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)

[...]
O>умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов>

Правильно, сравни с тем что было ранее, это одна из ошибок, на которую указал watchmaker.

Итак, зная размер строки X, мы можем выделить под неё буфер:
malloc(X) — возвращает указатель на выделенный буфер размера X, либо нулевой указатель в случае fail.

Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*.
Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно):
char *string = malloc(X);

Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
Re[12]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 21:59
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


O>>>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)

EP>[...]
O>>умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов>
EP>

EP>Правильно, сравни с тем что было ранее, это одна из ошибок, на которую указал watchmaker.

EP>Итак, зная размер строки X, мы можем выделить под неё буфер:

EP>malloc(X) — возвращает указатель на выделенный буфер размера X, либо нулевой указатель в случае fail.

EP>Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*.

EP>Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно):
EP>
EP>char *string = malloc(X);
EP>

EP>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?

Чтобы положить в нее свое значение
Re[13]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 22:10
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

EP>>Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*.

EP>>Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно):
EP>>
EP>>char *string = malloc(X);
EP>>

EP>>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?

O>Чтобы положить в нее свое значение


Откуда? из arr->substrings[i-1]?
То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
Как именно ты собрался это делать?
Re[14]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 18.04.14 04:17
Оценка:
O>>Чтобы положить в нее свое значение

EP>Откуда? из arr->substrings[i-1]?

EP>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
EP>Как именно ты собрался это делать?

map.name[k]=arr->substrings[i-1];
Re: invalid fastbin entry (free):
От: Кодт Россия  
Дата: 18.04.14 10:05
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):


Такое впечатление, что этот код был переписан с паскаля. Индекс от 1 до colls_num включительно, проверка нечётности (!!!), и т.п.
Можно я его просто начисто перепишу?
MAPPER make_mapper(SPLITTER *splitter)
{
    MAPPER mapper;
    int i;

    mapper.colls_num = splitter->colls_num / 2; /* сразу знаем количество */
    mapper.name  = (char**) malloc(mapper.colls_num * sizeof(char*));
    mapper.value = (char**) malloc(mapper.colls_num * sizeof(char*));

    for(i=0; i<mapper.colls_num; ++i)
    {
        mapper.name [i] = strdup(splitter->substrings[i*2  ]); /* не морочим себе голову, берём стандартную функцию аллокации строк */
        mapper.value[i] = strdup(splitter->substrings[i*2+1]);
    }

    return mapper;
}

Это если помещать каждую строку в отдельный блок.
А если хочется разместить все данные в одном блоке, чтобы mapper.name указывал на таблицу индексов, откуда ссылки вели бы на строки в этом же блоке, то НЕЛЬЗЯ делать realloc.
Потому что ты, тем самым, сбиваешь все указатели, которые были внутрь старого блока.

Делаем более чисто:
char* putback(char* /*in-out*/ *pblock, char const* str)
{
    char* block = *pblock;
    int size;
    size = strlen(str) + 1;

    strcpy(block, str); /* копируем строку */
    (*pblock) += size; /* двигаем указатель начала блока */
    return block; /* возвращаем адрес копии */
}

MAPPER make_mapper(SPLITTER *splitter)
{
    MAPPER mapper;
    int n, i;
    int len_names, len_values;
    char* block_names;
    char* block_values;

    n = splitter->colls_num / 2;

    /* считаем потребную память */
    len_names = 0;
    len_values = 0;
    for(i=0; i<n; ++i)
    {
        len_names  += strlen(splitter->substrings[i*2  ]) + 1; /* включая концевые нули */
        len_values += strlen(splitter->substrings[i*2+1]) + 1;
    }

    /* выделяем память */
    block_names  = (char*) malloc(n*sizeof(char*) + len_names *sizeof(char));
    block_values = (char*) malloc(n*sizeof(char*) + len_values*sizeof(char));

    /* настраиваем структуру */
    mapper.colls_num = n;
    mapper.name  = (char**) block_names;  block_names  += n*sizeof(char*);
    mapper.value = (char**) block_values; block_values += n*sizeof(char*);

    /* копируем строки */
    for(i=0; i<n; ++i)
    {
        mapper.name [i] = putback(&block_names,  splitter->substrings[i*2  ]);  
        mapper.value[i] = putback(&block_values, splitter->substrings[i*2+1]);
    }

    return mapper;
}
Перекуём баги на фичи!
Re[15]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 18.04.14 11:21
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>>>Чтобы положить в нее свое значение

EP>>Откуда? из arr->substrings[i-1]?
EP>>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
EP>>Как именно ты собрался это делать?
O>map.name[k]=arr->substrings[i-1];

Тут происходит копирование адреса, а не самой строки. Причём тот адрес который был раньше слева — затирается.

P.S. По всей видимости ты только начинаешь изучение C. Если в дальнейшем планируешь перейти на C++, то нет никакой необходимости сначала учить C — это только привьёт вредные привычки, которые к тому же порождают тормозной код.
Советую начать с книги Страуструпа — Programming -- Principles and Practice Using C++ (или на русском).
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.