LINUX.ORG.RU

segmentation fault

 ,


0

1

Отлаживаю баг в одном проекте, часть которого на писана на С++. Проблема в segmentation fault(SIGSEGV), программа падает. Где падает я узнал

Вот тут, после этого вызова

m_listener->onClose(m_id) //Listener* m_listener


m_listener это virtual метод класса.
class Listener {
public:
	virtual void onData(uint32_t id, TransportData data) = 0;
	virtual void onClose(uint32_t id) = 0;
};




Сам объект класса TransportSession, в котором падает, создается через

m_session = std::make_shared<TransportSession>(0, m_service, std::move(m_socket), this);


Какие могут быть вообще причины возникновения segmentation fault? Удалилась ссылка на m_listener? Проверить указатель как я читал, в С++ никак не возможно.
Делал
if(m_listener != NULL)
if(m_listener != nullprt)

бесполезно

★★★★

Проверить указатель как я читал, в С++ никак не возможно.

Возможно, но платформоспецифично.

после этого вызова

Посмотри что там в vtable, возможно метод остался pure и там std::terminate висит

SR_team ★★★★★ ()

А что говорит valgrind? В gdb пробовали смотреть что-то?

anonymous ()

Какие могут быть вообще причины возникновения segmentation fault?

Вангую: dangle m_listener pointer. Его скорее всего удалили, а указатель не занулили. valgrind (как предлагали выше) такое ловит.

bugfixer ★★ ()
Ответ на: комментарий от gobot

Ты о том, что такое pure virtual методы, в курсе вообще, макака клавиатурная?

anonymous ()
Ответ на: комментарий от bhfq
if(m_listener.get() != NULL){
	m_listener->onClose(m_id);
}



error: request for member ‘get’ ... in which is of pointer type ... (maybe you meant to use ‘->’ ?)

gobot ★★★★ ()
Ответ на: комментарий от bhfq

Сам сначала так прочитал: m_listener это походу raw pointer. Зачем ТС вообще упомянул что m_session это shared_ptr - непонятно, только народ с толку сбил.

bugfixer ★★ ()
Ответ на: комментарий от gobot

Я ничего не понял

Что-то мне подсказывает что зря Вы за это взялись. Попросите лучше кого-нибудь из знакомых Вам помочь это отладить. Здесь Вас скорее всего только грязью обольют. И в чём-то будут правы, потому как терпения разжёвывать Вам самые базовые вещи с нуля ни у кого не хватит.

bugfixer ★★ ()
Последнее исправление: bugfixer (всего исправлений: 1)
Ответ на: комментарий от gobot

что?

таблица указателей на виртуальные методы

Че?

virtual void foo() = 0; - чистый (pure) виртуальный метод. Для таких в vtable создаются методы, которые при вызове сразу роняют программу. А в vtable наследников, которые перегружают такие методы уже создается нормальный метод не роняющий программу. Из-за ошибки компилятора при девертуализации методов мог быть подставлен метод из не той vtable, но это маловероятно.

а?

Это функция для быстрого убийства программы, как правило, ее вызов прописан в чистых виртуальных методах

SR_team ★★★★★ ()

сделай onClose не абстрактным, а пустым. И попоробуй.

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

вместо так

virtual void onClose(uint32_t id) = 0;

напиши вот так

virtual void onClose(uint32_t id) {};
alysnix ()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от SR_team

Из-за ошибки компилятора при девертуализации методов мог быть подставлен метод из не той vtable, но это маловероятно.

ты чаво несешь-то тут? он запросто может вызвать абстактный, если -не определил его в классе наследнике, и/или вызвал из деструктора/конструктора класса в котором он еще абстратный.

alysnix ()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

он запросто может вызвать абстактный, если -не определил его в классе наследнике

Это тоже будет ошибкой компилятора - он не должен дать скомпилировать код если создается объект в котором есть чистые виртуальные методы

SR_team ★★★★★ ()
Ответ на: комментарий от bugfixer

Сам сначала так прочитал: m_listener это походу raw pointer. Зачем ТС вообще упомянул что m_session это shared_ptr - непонятно, только народ с толку сбил.

Кр4, я вот за этот вариант

SR_team ★★★★★ ()
Последнее исправление: SR_team (всего исправлений: 1)

backtrace делал? Не помогло?

kvpfs ()
Ответ на: комментарий от AntonI

Да ладно, valgrind уже посоветовали. Я бы санитайзеров предложил.

А народ по факту добрее оказался чем я думал - вон уже какие «полотенца» пошли ;) Так глядишь - и сдвинут дело с мёртвой точки.

bugfixer ★★ ()
Ответ на: комментарий от bugfixer

ТС чисто код зажал, взывает к Ванге по всей видимости.

bhfq ★★★★★ ()
Ответ на: комментарий от SR_team

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

Тем не менее pure virtual вполне может быть определён и вызван. Потренироваться можно на деструкторах.

bugfixer ★★ ()
Ответ на: комментарий от SR_team

Кр4,

Вас там много что ли?

я вот за этот вариант

Оно там выше уже ошибкой компиляции подтверждено.

bugfixer ★★ ()
Ответ на: комментарий от bugfixer
class A {
public:
  virtual void ff()=0; ///абстрактный метод

  void stub(){
    ff(); ///тут вызывается ff()
  }
  
  virtual ~A(){
    stub(); ///тут косвенно вызывается ff. компилятор этого не видит
 }
};

class B: public A {
public:
 void ff() override {}; ///реализуем ff
};

вот при деструкции B будет вызван абстрактный метод ff от A, поскольку он вызывается в деструкторе A.

alysnix ()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от gobot

Я ничего не понял

Бросай c++, это не твоё.

anonymous ()
Ответ на: комментарий от bugfixer

Зачем ТС вообще упомянул что m_session это shared_ptr - непонятно, только народ с толку сбил

Он вообще не понимает что к чему.

anonymous ()
Ответ на: комментарий от AntonI

Мы все учились прнемногу…

Ой да ладно, когда на форум приходили с вопросами не понимая основ?

anonymous ()
Ответ на: комментарий от alysnix

вот при деструкции B будет вызван

Я сам на интервью часто спрашиваю можно ли вызывать virtual из деструктора, можно мне было механику процесса не объяснять.

Вам очевидно что A::ff() может быть определён несмотря на то что он абстрактный? Вы никогда не видели pure virtual деструкторов и не задумывалась зачем так делают?

bugfixer ★★ ()
Ответ на: комментарий от bugfixer

Вы никогда не видели pure virtual деструкторов и не задумывалась зачем так делают?

зачем так делают - я не знаю, я так не делаю. я говорю как законно вызвать абстрактный метод.

alysnix ()

что в gdb? зачем огрызками код, покажи весь

hizel ★★★★★ ()
Ответ на: комментарий от anonymous

Я бывало приходил. Знание это то с чем ты уходишь получив ответ на вопрос, а не то с чем приходишь.

AntonI ★★ ()
Ответ на: комментарий от AntonI

ПМСМ лучше тупо в gdb загнать и всё, он аж место покажет в точности то в котором упадёт, заодно и слепок памяти можно будет изучить.

AKonia ★★ ()
Последнее исправление: AKonia (всего исправлений: 1)

m_listener это virtual метод класса

Нет, это указатель на родительский объект чисто виртуального класса. Тут сразу напрашивается то как вы его создаёте и как выглядит унаследованный класс от данного базового.

Проверить указатель как я читал, в С++ никак не возможно

GDB! GDB! GDB! Без разницы как и где, я рекомендую воспользоваться отладчиком - он вам покажет все интимные подробности вашей ошибки. Если не умеете из консоли, то смотрите встроенный в QtCreator отладчик и gdbfrontend, а также на gh есть gf1, ну и старичок cgdb - первые два проще, поэтому рекомендую взять их и посмотреть на состояние данных до строки на которой падает, более того можно просто gdb натравить на файл-слепок, по которому тот тыкнет в точное место в котором происходит падение, вплоть до уровней вложенности, впрочем если есть возможность пересобрать программу, то можно и просто запустить программу.

AKonia ★★ ()
Последнее исправление: AKonia (всего исправлений: 1)

У segmentation fault может быть только одна причина - память к которой ты обращаешься не выделена или по другой причине защищена от той операции которую ты над ней хочешь произвести.

pon4ik ★★★★★ ()
Последнее исправление: pon4ik (всего исправлений: 1)

Listener - это интерфейс, кто его реализует TransportSession или ещё кто из топика непонятно, а читать весь тред - не охота, возможно не одному мне.

Но, если стек-трейс кончается на m_listener->onClose(m_id) //Listener* m_listener (не после и не до, а в этой точке), то похоже на то, что в m_listener лежит мусор.

pon4ik ★★★★★ ()
Ответ на: комментарий от ox55ff

Хотя бы затем, чтобы полиморфно удалять наследников ;)

pon4ik ★★★★★ ()
Ответ на: комментарий от alysnix

вот при деструкции B будет вызван абстрактный метод ff от A, поскольку он вызывается в деструкторе A.

А можешь объяснить, почему так происходит? У объекта же указатель на vtable от B, и ff() от B по идее должна вызываться.

Ну и при прямом вызове stub() так и происходит. Это в деструкторе какие-то особые правила или как раз ошибка девиртуализации?

Ivan_qrt ★★★★★ ()
Ответ на: комментарий от PRN

А как у производного класса деструктор вызовется, если указатель как Listener* объявлен?

для того и делается virtual деструктор, что он вызывается как виртуальный метод, из таблицы вирт. методов у актуального обьекта. а вот если деструктор Listener не обьявлен виртуальным, то вызовется именно деструктор Listener, что скорее всего будет ошибкой(если у наследника свой деструктор),и неошибкой, если у наследника деструктора нет.

alysnix ()
Ответ на: комментарий от alysnix

Это был скорее риторический вопрос), возможно, я его сформулировал не очевидным образом)). Ты неплохо объясняешь, чаще какахами закидывают.

PRN ()
Ответ на: комментарий от Ivan_qrt

А можешь объяснить, почему так происходит? У объекта же указатель на vtable от B, и ff() от B по идее должна вызываться.

это стандарт языка и здравый смысл. деструктор первым делом переустанавливает указатель на vmt своего класса и понятно почему. потому что деструкторы потомков уже выполнились, и потомки больше «не существуют». пользоваться их функциональностью - неверно. например если вирутальный метод потомка использует обьект что деструктор потомка удалил. тогда вызов вирт метода этого потомка уже некорректен. и это правильная идеология для деструкторов

alysnix ()
Ответ на: комментарий от gobot

что?

хуёв сто

Че

хуй те в рот через плечё

а?

хуй на

anonymous ()
Ответ на: комментарий от alysnix

virtual void onClose(uint32_t id) {};

так не помогло, валится все равно

в отладчике жеж видно, какой адрес мусорный

Адрес m_listener там вот такой 0x46dd570. Как понять мусорный или нет?

gobot ★★★★ ()
Ответ на: комментарий от AKonia

Ну я и GDB пробовал, и в Visual Studio дебажил. Все, что я там увидел это адрес на который указывает m_listener, типа такого 0x46dd570. Что я должен с ним делать? Искать в памяти этот адрес?

посмотреть на состояние данных до строки на которой падает

пробовал и так. Если вызывать m_listener->onClose() до того как падает, то нормально вызывается

gobot ★★★★ ()
Ответ на: комментарий от Ivan_qrt

А можешь объяснить, почему так происходит?

Да: если коротко - то стандарт и здравый смысл. Когда исполняется A::~A() той части которая относится к классу B уже не существует, посему дергать за любые методы класса B - небезопасно. На самом деле в A::~A() context уже statically typed, так что в зависимости от code visibility в конкретном TU compiler может вообще с vtable не консультироваться. В общем случае приходится патчить vptr по мере раскручивания деструкторов.

bugfixer ★★ ()
Ответ на: комментарий от gobot

пробовал и так.

Вот Вам рецепт: добавляйте cout’s в конструктор и деструктор Listener (заодно this печатайте), и перед тем callsite onClose() где всё валится. А лучше друзей попросите помочь, пивком проставьтесь - и с пользой и приятно время проведёте ;)

bugfixer ★★ ()
Последнее исправление: bugfixer (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.