LINUX.ORG.RU

Сегфолт при вызове PHYSFS_close

 ,


0

1

Пытаюсь переписать одну древнюю обертку над PhysFS для использования с C++ стримами. Вроде бы все как надо, но при попытке чтения/записи при помощи этой обертки вылетает сегфолт в деструкторе вот в этом месте:

      if (PHYSFS_close(m_file) != 0)
        return nullptr;
Дело явно не в PhysFS, уже проверял, используя чистый API - открыл файл, записал несколько байт, успешно закрыл. Несколько раз перечитывал статью про внутреннее устройство std::streambuf, но так и не понял, где косяк. Подскажите пожалуйста, люди добрые, в каком месте копать причину сегфолта. Ссылка на полный исходник https://pastebin.com/EEsQcbRh

Ответ на: комментарий от DELIRIUM
#0  __PHYSFS_platformGrabMutex (mutex=0x0) at /usr/src/debug/dev-games/physfs-3.0.1-r1/physfs-3.0.1/src/physfs_platform_posix.c:387
#1  0x00007ffff7fb3499 in PHYSFS_close (_handle=0x41b7a0) at /usr/src/debug/dev-games/physfs-3.0.1-r1/physfs-3.0.1/src/physfs.c:2701
#2  0x00000000004048f7 in PhysFS::fbuf::close (this=0x7fffffffdd60) at ../physfs_streams.hpp:78
#3  0x0000000000403800 in PhysFS::fbuf::~fbuf (this=0x7fffffffdd60) at ../physfs_streams.hpp:20
#4  0x0000000000404a44 in PhysFS::ofstream::~ofstream (this=0x7fffffffdd58, vtt=0x405070 <VTT for PhysFS::ofstream>) at ../physfs_streams.hpp:230
#5  0x00000000004036a3 in PhysFS::ofstream::~ofstream (this=0x7fffffffdd58) at ../physfs_streams.hpp:230
#6  0x0000000000403557 in main (argc=1, argv=0x7fffffffdfc8) at ../main.cpp:15
onyxdaemon
() автор топика
Ответ на: комментарий от onyxdaemon

physfs_platform_posix.c:387 вот это место

int __PHYSFS_platformGrabMutex(void *mutex)
{
    PthreadMutex *m = (PthreadMutex *) mutex;
    pthread_t tid = pthread_self();
    if (m->owner != tid)
    {
        if (pthread_mutex_lock(&m->mutex) != 0)
            return 0;
        m->owner = tid;
    } /* if */

    m->count++;
    return 1;
} /* __PHYSFS_platformGrabMutex */

onyxdaemon
() автор топика

valgrind что говорит?

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

Там точно не ноль и не мусор?

Там точно ноль, это видно по бэктрейсу.

Дело может быть в повторном вызове close из деструктора буфера. В close не обнуляется m_file.

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

Не, вряд ли. Погуглил по «PHYSFS_platformGrabMutex», нашёл несколько тем. В эту функцию передаётся указатель на мьютекс, который инициализируется где-то внутри PhysFS, по идее вместе с вызовом PHYSFS_init. Но этого не происходит и в PHYSFS_platformGrabMutex передаётся NULL.

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

Прогнал в GDB кучей брейкпоинтов. Херня какая-то, почему-то деструктор стрима (и буфера) вызывается уже после того, как PhysFS деинициализирована. Поэтому void* mutex и обнулен. Что за магия... У меня PHYSFS_deinit вызывается здесь:

PHYSFS_init(argv[0]);
PHYSFS_setWriteDir(PHYSFS_getPrefDir("test", "test));

PhysFS::ofstream test("file.txt");
test << "qwerty";

PHYSFS_deinit();

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

Кавычки здесь пропустил случайно.

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

Деструкторы стрима буфера почему-то вызываются, когда библиотека деинициализирована (а деинициализация проходит уже в самом конце и по идее деструктор стрима должен вызываться раньше).

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

А покажите как вы используете ваши stream. Возможно деструктор буфера вызывается после отработки PHYSFS_deinit.

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

Ну так и есть, деструктор стрима вызывается уже после PHYSFS_deinit.

Вот так сделайте:

PHYSFS_init(argv[0]);
{
PHYSFS_setWriteDir(PHYSFS_getPrefDir("test", "test));

PhysFS::ofstream test("file.txt");
test << "qwerty";
}
PHYSFS_deinit();

BRE ★★
()
Последнее исправление: BRE (всего исправлений: 2)
Ответ на: комментарий от sniper21

Т.е. деструктор ofstream вызывается всегда в конце блока?

Конечно.

BRE ★★
()

Оберни свой m_file в какой-нибудь RAII холдер. Да хоть std::shared_ptr с PHYSFS_close в качестве deleter'а. И будет тебе счастье.

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

Херня какая-то, почему-то деструктор стрима (и буфера) вызывается уже после того, как PhysFS деинициализирована. Поэтому void* mutex и обнулен. Что за магия...

Ой, ХЗ. Это либо малоизвестная фича C++, либо вообще нестандартное расширение/баг компилятора.

Хотя нет. Это ты с ICQ < 70 полез в язык не изучив самых азов.

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

Разницы никакой, все равно деструктор стрима вызовется перед return 0 (в выше приведенном случае), если область видимости не ограничить. Ну а так да, совет полезный, лучше в unique_ptr завернуть.

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

Разницы никакой, все равно деструктор стрима вызовется перед return 0 (в выше приведенном случае)

деструктор вызовется, вопросов нет. но проблема не в деструкторе, а в двойном вызове close(). Еще точнее в 'double-free' в close(): он не чистит m_file после вызова после PHYSFS_close(m_file), и не проверяет нужно ли вообще делать PHYSFS_close()

лучше в unique_ptr завернуть.

в unique_ptr конечно лучше, правда придется явно написать тип финализатора тогда

Sectoid ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.