Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Умные указатели и Segmentation fault 
:(
    Опции темы
ChipNDale
Дата 13.2.2013, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 11.6.2010

Репутация: нет
Всего: 1



Приветствую.
Столкнулся с проблемой, которую даже не знаю как адекватно сформулировать, поэтому сейчас будет поток сознания. Если коротко: программа падает.
Подробнее.
Повсеместно используются умные указатели (std::shared_ptr и std::unique_ptr). Имеется некоторая вложенность объектов, которая примерно выглядит так:
Код

Application
  unique_ptr<Context>
    unique_ptr<Queue>
      shared_ptr<vector<shared_ptr<Job>>>
, где Job наследуется от boost::noncopyable.

Усугубляется это безобразие тем, объекты shared_ptr<Job> создаются в коде библиотеке, загружаемой во время выполнения и в сам контейнер попадают не сразу же, а пройдя еще через некоторые методы-объекты-контейнеры.
В общем, не вижу смысла приводить тут весь код: никто в здравом уме не будет разбираться во всей системе. В то же время не удалось написать короткий пример для воспроизведения проблемы.

Собственно, вопрос: если кто-нибудь сталкивался с падениями при использвании умных указателей, как вообще подходить к отладке и на что смотреть? 
Максимум, что я понял из бэктрейса, падение происходит где-то в деструкторе Queue при уничтожении его контейнера шаред поинтеров. Все дальнейшее мне мало о чем говорит, но все-таки ниже приложу сам бэктрейс.

В деструкторе Queue пробегался по всем объектам из контейнера и смотрел use_count - везде единички.

Временное решение проблемы - вектор указателей заменить на вектор объектов, для Job убрать наследование от boost::noncopyable. 

Бэктрейс:
Код

#0  0x000000000042e50a in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x6477c0)
    at /usr/include/c++/4.7/bits/shared_ptr_base.h:147
#1  0x000000000042d38d in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x648e28, 
    __in_chrg=<optimized out>) at /usr/include/c++/4.7/bits/shared_ptr_base.h:558
#2  0x00007ffff77264f4 in std::__shared_ptr<MyNamespace::Job, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x648e20, 
    __in_chrg=<optimized out>) at /usr/include/c++/4.7/bits/shared_ptr_base.h:813
#3  0x00007ffff77268d8 in std::shared_ptr<MyNamespace::Job>::~shared_ptr (this=0x648e20, __in_chrg=<optimized out>)
    at /usr/include/c++/4.7/bits/shared_ptr.h:93
#4  0x00007ffff7726af6 in std::_Destroy<std::shared_ptr<MyNamespace::Job> > (__pointer=0x648e20)
    at /usr/include/c++/4.7/bits/stl_construct.h:95
#5  0x00007ffff772691e in std::_Destroy_aux<false>::__destroy<std::shared_ptr<MyNamespace::Job>*> (__first=0x648e20, 
    __last=0x648ed0) at /usr/include/c++/4.7/bits/stl_construct.h:105
#6  0x00007ffff7726696 in std::_Destroy<std::shared_ptr<MyNamespace::Job>*> (__first=0x648e20, __last=0x648ed0)
    at /usr/include/c++/4.7/bits/stl_construct.h:128
#7  0x00007ffff772637c in std::_Destroy<std::shared_ptr<MyNamespace::Job>*, std::shared_ptr<MyNamespace::Job> > (
    __first=0x648e20, __last=0x648ed0) at /usr/include/c++/4.7/bits/stl_construct.h:155
#8  0x00007ffff77273e7 in std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > >::~vector (this=0x6475b8, __in_chrg=<optimized out>) at /usr/include/c++/4.7/bits/stl_vector.h:403
#9  0x00007ffff7727392 in __gnu_cxx::new_allocator<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > >::destroy<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > > (this=0x6475b0, __p=0x6475b8) at /usr/include/c++/4.7/ext/new_allocator.h:114
#10 0x00007ffff772734e in std::allocator_traits<std::allocator<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > > >::_S_destroy<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > > (__a=..., __p=0x6475b8) at /usr/include/c++/4.7/bits/alloc_traits.h:279
#11 0x00007ffff7727304 in std::allocator_traits<std::allocator<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > > >::destroy<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > > (__a=..., __p=0x6475b8) at /usr/include/c++/4.7/bits/alloc_traits.h:402
#12 0x00007ffff7727247 in std::_Sp_counted_ptr_inplace<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > >, std::allocator<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > >, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0x6475a0)
    at /usr/include/c++/4.7/bits/shared_ptr_base.h:410
#13 0x000000000042e516 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x6475a0)
    at /usr/include/c++/4.7/bits/shared_ptr_base.h:147
#14 0x000000000042d38d in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x647838, 
    __in_chrg=<optimized out>) at /usr/include/c++/4.7/bits/shared_ptr_base.h:558
#15 0x00007ffff7725c1e in std::__shared_ptr<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > >, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x647830, __in_chrg=<optimized out>)
    at /usr/include/c++/4.7/bits/shared_ptr_base.h:813
#16 0x00007ffff7725c38 in std::shared_ptr<std::vector<std::shared_ptr<MyNamespace::Job>, std::allocator<std::shared_ptr<MyNamespace::Job> > > >::~shared_ptr (this=0x647830, __in_chrg=<optimized out>) at /usr/include/c++/4.7/bits/shared_ptr.h:93
#17 0x00007ffff7725aaa in MyNamespace::Queue::~Queue (this=0x647830, __in_chrg=<optimized out>)
    at /MyNamespace/src/Queue.cpp:15
#18 0x0000000000436a3a in std::default_delete<MyNamespace::Queue>::operator() (this=0x649b28, __ptr=0x647830)
    at /usr/include/c++/4.7/bits/unique_ptr.h:63
#19 0x00000000004367d9 in std::unique_ptr<MyNamespace::Queue, std::default_delete<MyNamespace::Queue> >::~unique_ptr (
    this=0x649b28, __in_chrg=<optimized out>) at /usr/include/c++/4.7/bits/unique_ptr.h:173
#20 0x00000000004364f2 in Core::Context::~Context (this=0x649b20, __in_chrg=<optimized out>)
    at /Context.cpp:25
#21 0x000000000042e912 in std::default_delete<Core::Context>::operator() (this=0x7fffffffe018, __ptr=0x649b20)
    at /usr/include/c++/4.7/bits/unique_ptr.h:63
#22 0x000000000042d5f9 in std::unique_ptr<Core::Context, std::default_delete<Core::Context> >::~unique_ptr (
    this=0x7fffffffe018, __in_chrg=<optimized out>) at /usr/include/c++/4.7/bits/unique_ptr.h:173
#23 0x000000000042b1b8 in Application::~Application (this=0x7fffffffe010, __in_chrg=<optimized out>)
    at /src/Application.cpp:49
#24 0x0000000000438fd3 in main (argc=3, argv=0x7fffffffe158)
    at /src/main.cpp:8


Это сообщение отредактировал(а) ChipNDale - 13.2.2013, 17:36
PM MAIL   Вверх
borisbn
Дата 13.2.2013, 17:47 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 21
Всего: 135



Цитата(ChipNDale @  13.2.2013,  17:35 Найти цитируемый пост)
объекты shared_ptr<Job> создаются в коде библиотеке, загружаемой во время выполнения 

Библиотека откомпилирована тем же компилятором, что и основное приложение ? С теми же опциями компиляции ? С теми же STL-ными h-никами ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
ChipNDale
Дата 13.2.2013, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 11.6.2010

Репутация: нет
Всего: 1



Да, тут весь код свой, в одном "солюшне", соответственно компилятор один и его флаги задаются глобально в единственном месте.

Добавлено @ 18:03
Эм... Сейчас наугад удалил одну строчку, внезапно сегфолт пропал.
Детали такие:
Job находится в библиотеке, которая статически линкуется с основным приложением.
Приложение во время выполнения загружает динамическую библиотеку из которой получает фабрику для этих Job'ов.
А убрал я закрытие библиотеки с этой самой фабрикой. Т.е. закрывать-то ее по-хорошему, надо, но, кажется, что если это происходит до уничтожения объекта Job, то происходит такое падение. И мне пока не ясно почему так.

Upd: проверил теорию. Да, если сначала уничтожить все созданные объекты, а только потом закрыть загруженные библиотеки, то работает корректно. Но вопрос "почему так происходит" все еще актуален.

Это сообщение отредактировал(а) ChipNDale - 13.2.2013, 18:11
PM MAIL   Вверх
ChipNDale
Дата 13.2.2013, 18:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 11.6.2010

Репутация: нет
Всего: 1



Вот такой получился пример для воспроизведения.
main.cpp:
Код

#include <iostream>
#include <memory>

#include <dlfcn.h>

typedef std::shared_ptr<int> (*Factory)();

int main()
{
    std::shared_ptr<int> obj;

    void* handle = dlopen("./libfactory.so", RTLD_LAZY);

    if (!handle)
    {
        std::cerr << dlerror() << std::endl;
        return 1;
    }

    Factory f;
    *reinterpret_cast<void**>(&f) = dlsym(handle, "create");

    char* error = dlerror();

    if (error)
    {
        std::cerr << error << std::endl;
        return 1;
    }

    obj = f();
    dlclose(handle);

    return 0;
}


factory.cpp:
Код

#include <memory>

extern "C" std::shared_ptr<int> create()
{
    return std::make_shared<int>();
}


Компиляция:
Код

g++ -std=c++11 main.cpp -ldl -o test

g++ -std=c++11 -fPIC -c factory.cpp
g++ -shared factory.o -o libfactory.so


Запуск:
Код

$ ./test 
Segmentation fault (core dumped)

PM MAIL   Вверх
mes
Дата 13.2.2013, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



есть простое правило, кто создал, тот удаляет..  smile 


--------------------
PM MAIL WWW   Вверх
maxim1000
Дата 13.2.2013, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 1
Всего: 110



подозреваю, что если в DLL'ке CRT используется, как статическая библиотека, то и куча создаётся на эту DLL'ку, и умирает с её выгрузкой

если же CRT используется, как DLL всеми модулями, думаю, одной причиной для падения будет меньше

Добавлено через 1 минуту и 9 секунд
хм... перечитал, понял, что не для Visual Studio, но для другой платформы/инструментов может тоже такое быть


--------------------
qqq
PM WWW   Вверх
ChipNDale
Дата 13.2.2013, 19:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 11.6.2010

Репутация: нет
Всего: 1



Цитата(mes @  13.2.2013,  18:57 Найти цитируемый пост)
есть простое правило, кто создал, тот удаляет.. 

Если бы использовались разные компиляторы или несогласованные способы выделения/освобождения памяти, то согласен - это поможет защититься. В моем же случае таких разногласий нет и я использую смарт поинтеры как раз для того, чтобы не приходилось следить за временем жизни каждого отдельного объекта.


Цитата(maxim1000 @  13.2.2013,  19:09 Найти цитируемый пост)
подозреваю, что если в DLL'ке CRT используется, как статическая библиотека, то и куча создаётся на эту DLL'ку, и умирает с её выгрузкой

Вероятно, что-то такое и происходит. А можно ли с помощью чего-нибудь посмотреть и получить более-менее наглядную картину? (а пока попробую потерзать гугл сомнительными запросами)
PM MAIL   Вверх
xvr
Дата 14.2.2013, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(ChipNDale @  13.2.2013,  19:21 Найти цитируемый пост)
А можно ли с помощью чего-нибудь посмотреть и получить более-менее наглядную картину?

Посмотрите objdump'ом и ldd, где находятся new/delete/malloc/free в основной программе и в .so модуле. Если они у каждого локальные - будут проблемы. Если берутся из одной и той же внешней .so - то проблем быть не должно
Еще можно глянуть в реализацию shared_ptr<> - что именно используется для удаления объекта (подозреваю, что банальный delete, но кто знает ... )


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0667 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.