Исследование плохой ссылки указателя free () - PullRequest
1 голос
/ 01 июня 2011

Моя программа сильно падает в унитарном тесте из-за вызова free () неверного указателя с таким сообщением об ошибке:

*** glibc detected *** /home/user/main.out: free(): invalid pointer: 0x006d0065 ***

Код выглядит примерно так:

// constructor is MyObj( const std::string & ) 
// and copies the string in its own std:string member
MyObject *obj = new MyObject("some string arg");
if(obj->isValid)
{
   log("Success\n");
}
delete obj; // if I remove this, the program doesn't crash...

Мои исследования прошли через это:

  1. Я пытался отследить созданные и свободные указатели, но это происходит в другом адресном пространстве, я получаю (успешные) удалениякак это: Delete buffer @0x850ed0.Поэтому я подозреваю, что что-то пытается освободить статический указатель на символ.Кроме того, адрес остается неизменным после нескольких попыток, что меня утешает в этом предикате.

  2. Я не могу использовать GDB, потому что платформа, которую я использую, похоже, выручает:

    Program received signal SIGABRT, Aborted.
    [Switching to Thread 0x344314e8 (LWP 1443)]
    0x2a3dd658 in raise () from /lib/libc.so.6
    (gdb) bt
    #0 0x2a3dd658 in raise () from /lib/libc.so.6
    #1 0x2a3dea2c in abort () from /lib/libc.so.6
    Backtrace stopped: frame did not save the PC

  3. Я пытался использовать hexdump для вывода адреса в программе, по которой free () завершается с ошибкой следующим образом: hexdump -C ~/main.out -s 0x6d0000 -n 2000

    Это дает мне это (ошибка free(0x6d0065)):

    006d0060 e8 32 06 00 2c e6 02 5f 5a 4e 4b 53 73 34 66 69 |.2..,.._ZNKSs4fi| 006d0070 6e 64 45 63 6a 00 ab 00 00 00 01 3e 58 00 00 1d |ndEcj......>X...|

    Это выглядит как функция std :: string, что довольно странно ... Я подумал, что это может быть неправильное использование hexdump, так как память перемещается, когдапрограмма загружается в память.

  4. Я пытался readelf ~/main.out -a | grep 6d0065 безрезультатно (не дает никакого удара)

Я не профессионал в отладке в этих условиях;Есть ли у вас какие-либо идеи о том, как я могу получить, что этот адрес означает для программы?

Редактировать:

  • Программа работает на встроенномплатформа (SH4);который не поддерживается valgrind (очень печально ...).

  • Еще несколько подробностей о том, что делает этот класс: он использует библиотеку CUrl для извлечения XMLфайл в Интернете, а затем приступает к его анализу с помощью библиотеки pugixml .

Ответы [ 3 ]

1 голос
/ 01 июня 2011

Дикий выстрел в темноте ... У вас есть базовый класс, у которого нет виртуального деструктора, и вы фактически создаете экземпляр производного класса и сохраняете результат нового в указателе на базу.Вы удаляете через базовый указатель, и неопределенное поведение в данном конкретном случае вызывает этот эффект.

Почему я так считаю?Указатель, переданный на free, не возвращается malloc, так как он является нечетным адресом, он не может быть правильно выровнен, а malloc всегда обеспечивает выровненные блоки памяти.Это означает, что память, которую указатель new возвратил, и сохраненный указатель имеют смещение, которое указывает, что это, вероятно, базовый класс.Если бы у класса был виртуальный деструктор, то delete мог бы определить наиболее производный тип объекта, и при этом он исправил бы указатель для ссылки на адрес, который был выделен с помощью new.Без виртуального деструктора delete преобразуется в obj->~MyObject(); free( obj ); без исправления смещения.

Еще одна вещь, которая может вызвать проблемы такого же типа, - выделение с помощью new[] и освобождение с * 1014.* (new[] выделит дополнительное место для хранения количества элементов, обычно перед возвращаемым указателем).Опять же, проблема заключается в том, что указатель, который передается в free реализацией delete, не исправляется в соответствии с указателем, возвращаемым malloc ... Но в этом конкретном случае смещение, вероятно, не будетнечетное число.

0 голосов
/ 02 июня 2011

Хорошо, наконец-то прибил ошибку.

Для тех, кто заинтересован, это была структура, которая не обнулялась в конструкторе класса, использующего ее.

Схема была такой:

MyObj ---> BaseClass ---> structure member not initialized

Поскольку эта структура содержит некоторые указатели на строки, проверка NULL не удалась, и я освободил бы неверный указатель.

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

Оглядываясь назад, я думаю, я мог бы найти это * на 1014 * путь * на 1015 * быстрее с работающей отладкой GDB. Я думаю, мне придется разобраться в этом вопросе.

0 голосов
/ 01 июня 2011

Ваш класс MyObject делает что-то очень, очень плохое.

И вы всегда (ну, почти всегда) можете использовать отладчик. В некоторых областях, таких как программирование в режиме реального времени, иногда бывает сложно, но здесь это не так.

Чтобы использовать отладчик осмысленно, ваш код должен быть скомпилирован с включенной отладкой, опция -g с компилятором GNU.

РЕДАКТИРОВАТЬ: я думаю, что "делать что-то очень, очень плохо" заключается в том, что класс удаляет то, что он не имеет никакого делового удаления. Например:

class MyObject {
public:
    MyObject(const char * strarg) : str(strarg) {}
    ~MyObject() { delete str; }
private:
    const char * str;
};
...