Добрый день.
Имеется программа использующая несколько разделяемых библиотек (boost, stlport и др...) и, в том числе, pqxx.
Если программу собирать с флагом -O2, то все работает замечательно, а вот если с -O0 то она будет падать с Segmentation Fault и в стеке будет следующее:#0 0x001b043e in malloc_consolidate () from /lib/tls/libc.so.6
#1 0x001afa59 in _int_malloc () from /lib/tls/libc.so.6
#2 0x001aedfd in malloc () from /lib/tls/libc.so.6
#3 0x00e3183f in makeEmptyPGconn () at fe-connect.c:1839
#4 0x00e300fe in PQconnectStart (conninfo=0x0) at fe-connect.c:321
#5 0x00e300c2 in PQconnectdb (conninfo=0x0) at fe-connect.c:286
#6 0x0819ee10 in connection (this=0x9715174, ConnInfo=0x9714530 "dbname=...") at ../include/pqxx/connection_base.hxx:187
...Хотелось бы понять почему так происходит и как это исправить?
>
>Хотелось бы понять почему так происходит и как это исправить?1. Скорее всего ошибка не связана с malloc, т.к. на всех остальных миллионах компьютеров malloc работает нормально.
2. Скорее всего ошибка не связана с libpq++, т.к. валится все-таки в malloc.Вывод - кто-то портит память, malloc работает с уже запорченной кучей. Маловероятно что это из-за оптимизации компилятора. Просто в случае -O2 _последствия_ получаются несколько иными (из-за иной раскладки страниц кода и данных) и в данном месте нет падения.
Ищите кто кучу портит.
>Ищите кто кучу портит.а как можно найти того кто портит кучу?
есть ли инструменты для этого?
>есть ли инструменты для этого?Да, куча всяких. Первое что попадается на глаза - Electric Fence
>>есть ли инструменты для этого?
>
>Да, куча всяких. Первое что попадается на глаза - Electric Fenceспасибо. попробую
>Да, куча всяких. Первое что попадается на глаза - Electric FenceElectric Fence ничего не показывает. Программа просто сваливается в coredump в разных местах точно так же как и без него...
Я бы попробовал valgrind'ом ковырнуть
>Electric Fence ничего не показывает. Программа просто сваливается в coredump в разных
>местах точно так же как и без него...именно так же? Принцип работы Efence - валиться в случае прострела в память...
А Valgrind действительно хорошая штука. Смотрите в логе Invalid write'ы и Invalid read'ы
>именно так же? Принцип работы Efence - валиться в случае прострела в
>память...именно что также, как будто Efencа и в помине нет...
>А Valgrind действительно хорошая штука. Смотрите в логе Invalid write'ы и Invalid
>read'ыДа, действительно они есть:
==9480== Invalid read of size 4
==9480== at 0x4266901: __pthread_mutex_unlock_usercnt (in /lib/tls/libpthread-0.60.so)
==9480== by 0x426697F: pthread_mutex_unlock (in /lib/tls/libpthread-0.60.so)
==9480== by 0x806B448: CCriticalSectionHolder::unlock() (CriticalSection.h:73)
...
==9480== Address 0xBEFFA00D is just below the stack ptr. To suppress, use: --workaround-gcc296-bugs=yes==9480== Invalid write of size 4
==9480== at 0x426690E: __pthread_mutex_unlock_usercnt (in /lib/tls/libpthread-0.60.so)
==9480== by 0x426697F: pthread_mutex_unlock (in /lib/tls/libpthread-0.60.so)
...==9480== Syscall param futex(futex) points to unaddressable byte(s)
==9480== at 0x4269791: __lll_mutex_unlock_wake (in /lib/tls/libpthread-0.60.so)
==9480== by 0x426697F: pthread_mutex_unlock (in /lib/tls/libpthread-0.60.so)
==9480== by 0x806B448: CCriticalSectionHolder::unlock() (CriticalSection.h:73)
...
==9480== Address 0xBEFFA001 is not stack'd, malloc'd or (recently) free'dкак понять почему так получается?
и что означают загадочные строчки "Address 0xBEFFA00D is just below the stack ptr", "Address 0xBEFFA001 is not stack'd, malloc'd or (recently) free'd"?а вот финальный аккорд на безобидном std::map::find():
==9480== Invalid read of size 4
==9480== at 0x8067D28: _STL::_Rb_tree_node<_STL::pair<_STL::basic_string<...
==9480== by 0x80673B3: _STL::_Rb_tree_iterator<_STL::pair<_STL::basic_string<...
==9480== by 0x8066884: _STL::map<_STL::basic_string<char, _STL::char_traits<...
==9480== by 0x80645F4: main
==9480== Address 0xAC is not stack'd, malloc'd or (recently) free'd
==9480==
==9480== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==9480== Access not within mapped region at address 0xAC
>==9480== Invalid read of size 4
>==9480== at 0x4266901: __pthread_mutex_unlock_usercnt (in /lib/tls/libpthread-0.60.so)
>==9480== by 0x426697F: pthread_mutex_unlock (in /lib/tls/libpthread-0.60.so)
>==9480== by 0x806B448: CCriticalSectionHolder::unlock() (CriticalSection.h:73)Скорее всего проблема в адресе переменной типа pthread_mutex_t, которая передаётся pthread_mutex_unlock(). Адрес этот битый. Ищите проблему начиная с обёртки для мьютекса(CCriticalSectionHolder).
>==9480== Invalid write of size 4
>==9480== at 0x426690E: __pthread_mutex_unlock_usercnt (in /lib/tls/libpthread-0.60.so)
>==9480== by 0x426697F: pthread_mutex_unlock (in /lib/tls/libpthread-0.60.so)Проявление той же проблемы.
>==9480== Syscall param futex(futex) points to unaddressable byte(s)
>==9480== at 0x4269791: __lll_mutex_unlock_wake (in /lib/tls/libpthread-0.60.so)
>==9480== by 0x426697F: pthread_mutex_unlock (in /lib/tls/libpthread-0.60.so)
>==9480== by 0x806B448: CCriticalSectionHolder::unlock() (CriticalSection.h:73)Проявление той же проблемы.
>==9480== Address 0xBEFFA001 is not stack'd, malloc'd or (recently) free'dАдрес связанный с вышеописанной проблемой пренадлежит ни стеку, ни куче. Т.е. имеет место прострел.
>как понять почему так получается?
Отлаживать :) Внимательно проследить цикл жизни проблемных объектов, включая копирование.
>и что означают загадочные строчки "Address 0xBEFFA00D is just below the stack ptr"
Адрес располжен ниже указателя стека. Т.е. Той области, до которой стек не дорос. Часто такое бывает при выделении объекта на стеке внутри функции и последующей попытке использовать его вне этой функции.
>, "Address 0xBEFFA001 is not stack'd, malloc'd or (recently) free'd"?
Адрес связанный с вышеописанной проблемой пренадлежит ни стеку, ни куче.
>[оверквотинг удален]
>==9480== Invalid read of size 4
>==9480== at 0x8067D28: _STL::_Rb_tree_node<_STL::pair<_STL::basic_string<...
>==9480== by 0x80673B3: _STL::_Rb_tree_iterator<_STL::pair<_STL::basic_string<...
>==9480== by 0x8066884: _STL::map<_STL::basic_string<char, _STL::char_traits<...
>==9480== by 0x80645F4: main
>==9480== Address 0xAC is not stack'd, malloc'd or (recently) free'd
>==9480==
>==9480== Process terminating with default action of signal 11 (SIGSEGV): dumping core
>
>==9480== Access not within mapped region at address 0xACТак как мап хранит копии объектов, думаю проблема в нём самом. Проследите его жизненный цикл.
Удачи.
спасибо за помощь!
буду разбираться...
стал внимательнее смотреть как собирается проект, и как собирались библиотеки к нему,
увидел что одна из библиотек (как раз та, где сидит обертка к мьютексу) собиралась с ключом
-D_GNU_SOURCEпересобрал проект с этим же ключом - все заработало, все проблемы исчезли.
что за чудеса? GNUшный стандарт компиляции так сильно отличается от того что по умолчанию?
>[оверквотинг удален]
>
>увидел что одна из библиотек (как раз та, где сидит обертка к
>мьютексу) собиралась с ключом
>-D_GNU_SOURCE
>
>пересобрал проект с этим же ключом - все заработало, все проблемы исчезли.
>
>
>что за чудеса? GNUшный стандарт компиляции так сильно отличается от того что
>по умолчанию?а нет. поторопился я, закралась опция -O2 с которой исчезают проблемы, а -D_GNU_SOURCE не влияет на самом деле.
Разобрался.Проблема заключалась в том, что было два разных класса с одним названием CCriticalSection (один в программе, а один в разделяемой библиотеке). После переименования одного из классов все стало нормально работать.
Спасибо всем за помощь.
>Проблема заключалась в том, что было два разных класса с одним названием
>CCriticalSection (один в программе, а один в разделяемой библиотеке).Кстати, а есть ли способ заставить компилятор ругаться на такие ситуации, или это только вручную можно отследить?
>Кстати, а есть ли способ заставить компилятор ругаться на такие ситуации...?Вряд ли. Компилятор не знает чего вы хотите, он лишь транслирует код. Может вы хотите именно разные классы использовать?
>Кстати, а есть ли способ заставить компилятор ругаться на такие ситуации, или
>это только вручную можно отследить?К сожалению, описанная проблема может быть отловлена в лучшем случае линкером, а в худшем - никем.
Линкер из GNU binutils способен поймать описанную проблему в случае, когда библиотека явно "линкуется" с основной программой и "одноименный" класс имеет хотя бы один не-inline метод. Прочие ситуации - на совести программиста.
>>Проблема заключалась в том, что было два разных класса с одним названием
>>CCriticalSection (один в программе, а один в разделяемой библиотеке).
>
>Кстати, а есть ли способ заставить компилятор ругаться на такие ситуации, или
>это только вручную можно отследить?если ваш класс будет сидеть в своём пространстве имён, и для доступа к нему будет использоваться full qualified name - может быть проблема решиться сама собой?
>если ваш класс будет сидеть в своём пространстве имён, и для доступа
>к нему будет использоваться full qualified name - может быть проблема
>решиться сама собой?а чем это отличается от переименования класса?
проблема была в том, что я не знал, что есть два класса с одинаковым именем
>а чем это отличается от переименования класса?Ничем не отличается.
>проблема была в том, что я не знал, что есть два класса
>с одинаковым именемВ стандарте C++ сие именуется "one definition rule" и, по сути дела,
оставлено на откуп программиста. Пригодных к использованию инструментов
для автоматизации решения такого рода задач (в принципе, смежных с
рефакторингом) для C++ я, увы, не видел.