Double free or corruption linux

Валится приложение с double free or corruption (fasttop)

Разрабатываю многопоточное приложение на Qt. Вел разработку под Windows + MinGW. Теперь переношу под Linux.

Есть некоторые сложности, понимаю, что не в платформе дело, а в допущенной где-то ошибке, но приложение работало без падений под Windows, а в Linux после нескольких минут «падает» с выдачей следующего: http://pastebin.com/DctNvtZt

Так как я не силен в gdb, подскажите методику, как выявить где именно проблема? Т.е. хотя бы с какого места ковырять? Спасибо.

Для тех, кто не знает английского, перевожу: ты два раза совобождаешь кусок памяти. Запусти свой бинарник под gdb, а после остановки выполни «bt», чтобы увидеть бактрейс, указывающий на место возникновения ошибки. А потом ищи, где ты лишний раз ошибочно высвобождаешь эту область памяти.

Правда. возможно ты выходишь за пределы выделенной области памяти. Тогда лучше остальных поможет valgrind.

К последним версиям QtCreator прикрутили valgrind.
В меню Analyze->Valgrind Memory Analyzer

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

Источник

double free or corruption (!prev)

При запуске приложения со следующей функцией

Если я убираю этот free, все работает — но ведь мусор-то тогда накапливается! Судя по MSG, free явно вызывается в первый раз, но почему-то приводит к такой странной ошибке. С чем это может быть связано?

Что именно в слове «corruption» непонятно?

pix не может быть больше vmax (да и падает программа все время на free, а иначе ошибка была бы, наверное, другая — corrupted double-linked list, например).

С указателями тоже понятно: *bp++ означает как раз *(bp++).

Что именно в слове «corruption» непонятно?

Непонятно, чего там повреждено-то могло быть?

> Непонятно, чего там повреждено-то могло быть?

Ыыыы. я так подозреваю, что ты вышел за границу массива hist. Убери запись в него и прогони программу — если ошибка исчезнет, ты портишь память.

Убери запись в него и прогони программу — если ошибка исчезнет, ты портишь память.

Точно, нашел ошибку. Совсем уже голова не варит: в цикле

Если бы ошибки с alloc’ами были более понятными (например, написали бы: segfault), было бы проще найти ошибку.

> Если бы ошибки с alloc’ами были более понятными (например, написали бы: segfault), было бы проще найти ошибку.

Тебе уже много раз сказали — пользуйся языками высокого уровня, там таких ошибок не бывает. Тебе, кстати, еще повезло — удачно память испортил, а часто это проходит незамеченным (а valgrind ты явно не используешь).

Не мешай человеку писать программу. Пристал тут со своими валгриндами и прочими фундаментальными проблемами очередей.

Валгриндами действительно не пользуюсь. А С по мне — язык достаточно высокого уровня (не ассемблер, все-таки).

Сейчас вот с очередной проблемой столкнулся: как mmap’ить один и тот же набор буферов v4l2, чтобы можно было обрабатывать видео одновременно в двух неродственных процессах (не хочется вручную выделять дополнительные буферы и копировать туда каждый кадр, когда v4l2 и так по идее предоставляет такую возможность).

Но, эту тему я, наверное, подниму завтра — если сам не разберусь.

Сейчас вот с очередной проблемой столкнулся: как mmap’ить один и тот же набор буферов v4l2, чтобы можно было обрабатывать видео одновременно в двух неродственных процессах (не хочется вручную выделять дополнительные буферы и копировать туда каждый кадр, когда v4l2 и так по идее предоставляет такую возможность).

Делаешь mmap() с MAP_SHARED, драйверу буфера через V4L2_MEMORY_USERPTR задаёшь из этого сегмента.

Читайте также:  Linux from scratch что это

А С по мне — язык достаточно высокого уровня

Это ты Коммон Лисп с Хаскеллями не видел.

драйверу буфера через V4L2_MEMORY_USERPTR задаёшь из этого сегмента.

Хотелось использовать MMAP, а не USERPTR (т.к. через буферы пользователя тормознутее работает). Ну, этим буду заниматься завтра (в домашнем компьютере TV-тюнера нет).

Это ты Коммон Лисп с Хаскеллями не видел.

Да мне чего только не предлагали изучать, вплоть до IDL 🙂 Но, думаю, лучше не распыляться. Так я только C и JavaScript не знаю (а об остальных понятия не имею), а то еще несколько языков буду не знать и доставать всех расспросами 🙂

Вообще, хочу посоветовать: пишите код так, как будто тот, кто его будет читать — это убийца-маньяк и он знает, где Вы живёте. То есть, избегайте конструкций вида x++ или x= (exp) ?y:z;
Лучше напишите
x += 1
или
if (exp)
<
x=y;
>
else
<
x=z;
>
здесь, жертвуя красотой/лаконичностью кода, Вы уважаете время того, кто потом просматривает код. Всё равно толковый оптимизатор в конечном итоге сделает одинаковый код в обеих случаях; однако при этом время, затраченное человеком на осознание кода, на несколько порядков ценнее времени, затраченного компилятором на преобразование кода в машинные команды. «Человек ценнее компьютера» — это первейшая аксиома (которая, кстати, частенько помогает решить множество логических ошибок в коде из-за чрезмерного увлечения лаконичностью и краткостью).

пишите код так, как будто тот, кто его будет читать — это убийца-маньяк и он знает, где Вы живёте.

Здесь уже, как говорится, на вкус и на цвет. Во многих учебниках, которые я читал, авторы наоборот советуют пользоваться конструкциями с префиксными/постфиксными инкрементами/декрементами, условными операциями вида (a)?b:c и т.п. сокращениями. Другие, как вы, советуют идти в ущерб лаконичности, но в пользу удобочитаемости. Я, честно говоря, не люблю, когда в одном файле больше трех-четырех сотен строк, поэтому стараюсь по возможности сокращать код (хотя это, с другой стороны, и неправильно) и распределять его по файлам (например, этот «проект» состоит из

12 сишных и десятка заголовочных файлов).

> избегайте конструкций вида x++ или x= (exp) ?y:z;

what’s wrong with ‘x= (exp) ?y:z;’?

Вы уважаете время того, кто потом просматривает код.

Скорее наоборот — не уважаете. Меня лично бесит стиль вида

такое впечатление, что у его автора был приступ словесного поноса^W^Wграфомании — 8 строк вместо одной (и да, время на чтение зависит и от количества строк).

Впрочем, это оффтопик и никак не делает Си языком высого уровня.

> Во многих учебниках, которые я читал, авторы наоборот советуют пользоваться конструкциями с префиксными/постфиксными инкрементами/декрементами, условными операциями вида (a)?b:c и т.п. сокращениями.
Это теоретики/академики

Другие, как вы, советуют идти в ущерб лаконичности, но в пользу удобочитаемости.

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

Ну три-четыре СОТН строк — это маловато. Нома под тысячу-полторы, но при этом желательно, чтобы функции в файле были не больше 60-120 строк (два-три экрана по PageUp/PageDown)

(хотя это, с другой стороны, и неправильно)

Почему неправильно? Пока проект из разряда «наклёпано на коленке для сиюминутной задачи», то и решение в одном мегабайтном исходнике сгодится. Но как только этот проектик становится достоянием общественности, то лучше, конечно, потратить немного времени на разбивку этого мегового файла по логическим блокам(функциям по назначению; по классам если ООП и т.п.) для упрощения понимания остальными людьми. И даже если при этом файлы будут по полкило — всё равно, это будет логически разделено и по человечески оправдано. Компилятор всё простит 😉

Читайте также:  Как поменять номера дисплеев windows

> Скорее наоборот — не уважаете. такое впечатление, что у его автора был приступ словесного поноса^W^Wграфомании — 8 строк вместо одной (и да, время на чтение зависит и от количества строк).

Нет-нет, не поймите как оскорбение Вас лично или всех тех людей, которые подобные конструкции склонны воспринимать как недостаток опыта. это не так. Тут палка о двух концах: либо человек, написавший подобное, действительно начинающий чайник; либо написавший подобное осознаёт, что его код будут читать тысячи людей и не все из них смогут сходу прочитать мудрённые конуструкции (а унарные и тринарные операции — это частный случай мудрённых конструкций). То есть, воспринимайте такое упрощение кода не проявление неувашения (хотя профи может вполне обоснованно воспринять подобное как неуважение к нему лично) — воспринимайте это как попытку помочь воспринять собственный код как можно большим числом людей в как можно сжатые сроки. Понимаю, что всем не угодить, однако и угождать только лишь меньшей части программеров-прыфессионалов тоже не стоит (не все будущие потенциальные патчеры являются профессиональными программистами).

Как-то так, в угоду большинству во имя жизни проекта 🙂

> Нет-нет, не поймите как оскорбение Вас лично или всех тех людей, которые подобные конструкции склонны воспринимать как недостаток опыта

Ну это ты назвал меня теоретиком и академиком %) Стиль, за который ты ратуешь — это пример «обжегся на молоке — дуешь на воду». Никакой ясности он не способствует.

> Ну это ты
Ок, с Вами мы не пересекались в негативном плане, посему принимаю приближение на «ты» 🙂 Далее на «ты», если не будет возражений.

Ну это ты назвал меня теоретиком и академиком %)

Вообще-то, не я называл :). Вероятно, это ты себя причислил; а на меня взвалил груз ответственности за классификацию ;). Просто моя классификация совпала с твоим мировозрением. Что не означает, что я утверждал, что ты теоретик и академик 🙂 Впрочем, это уже демагогия (ненавижу жонглирование словесями).

По поводу удобочитаемости: для тебя, вероятно, подобный код и будет снижением удобочитаемости, но для десятка человек это будет восприятием кода на их уровне. Тут остаётся только уповать на то, что ты лично не отвернёшься от подобного проекта(стиль кода не отвратит тебя) и таки опубликуешь назревший собственный патч безопасности, при этом пять «хомячков» опубликуют патчи для добавления свистоперделок.

Хотелось использовать MMAP, а не USERPTR (т.к. через буферы пользователя тормознутее работает). Ну, этим буду заниматься завтра (в домашнем компьютере TV-тюнера нет).

Отличие только в том, кто выделяет буфер: драйвер или юзер.

Да мне чего только не предлагали изучать, вплоть до IDL 🙂 Но, думаю, лучше не распыляться. Так я только C и JavaScript не знаю (а об остальных понятия не имею), а то еще несколько языков буду не знать и доставать всех расспросами 🙂

Учиться надо всю жизнь.

Читайте также:  Что такое core dump linux

Это точно. Но я считаю более полезным проштудировать лишний раз мат. анализ, оптику и астрофизику (ну, или «Все про ТеХ» Кнута оживить в воспоминаниях), чем новый ЯП изучать.

По поводу MMAP V4L2

Не хочу создавать отдельную тему, но приведу вкратце решение.

С MMAP и USERPTR я разобрался. MMAP’ом «поделиться» видеопамятью, к сожалению, нельзя. Зато можно при помощи флага V4L2_MEMORY_USERPTR заставить v4l2 выделять память в буферы пользователя.

Сначала я пытался сделать mmap на /dev/null с разными смещениями. Естественно, ничего не получилось. Тогда я решил сделать mmap через виртуальные файлы из shm_open:

В читающем процессе буферы инициализируются так:

С MMAP и USERPTR я разобрался. MMAP’ом «поделиться» видеопамятью, к сожалению, нельзя.

Какая такая видеопамять? V4L(2) принимает данные от устройства (самостоятельно, либо просит об этом DMA-контроллер устройства) и кладёт их в буферы, которые лежат в обычной памяти.

Зато можно при помощи флага V4L2_MEMORY_USERPTR заставить v4l2 выделять память в буферы пользователя.

С USERPTR ядро память не выделяет, а использует ту, которую подсунул юзер. Читай исходники ядра.

Сначала я пытался сделать mmap на /dev/null с разными смещениями. Естественно, ничего не получилось.

O_o mmap() на /dev/null. o_O

Тогда я решил сделать mmap через виртуальные файлы из shm_open:

Вообще-то можно mmap() делать и без бэкинга на файл. man mmap.

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

С USERPTR ядро память не выделяет, а использует ту, которую подсунул юзер. Читай исходники ядра.

Ну, немного не так выразился. Я имел в виду, что при помощи этого флага v4l2 будет использовать буферы пользователя для «сбрасывания» данных.

Извиняюсь, «очепятался»: /dev/zero. Почитайте Стивенса — mmap’ировать через /dev/zero удобно.

Да, до меня только сейчас дошло, что можно было сделать mmap на все четыре буфера одним куском, и вычислять адрес буфера как указатель + длина * номер.

Вообще-то можно mmap() делать и без бэкинга на файл. man mmap.

Как? Разве без файла ядро сможет узнать, что две различные области памяти надо синхронизовать?

> То есть, избегайте конструкций вида x++ или x= (exp) ?y:z;

Слушай,норкоман, иди излагать свои приходы в толксы.

> Во многих учебниках, которые я читал, авторы наоборот советуют пользоваться конструкциями с префиксными/постфиксными инкрементами/декрементами, условными операциями вида (a)?b:c и т.п. сокращениями.

Тренарным оператором надо пользоваться осторожно, а пре- и постфиксные операторы — обязательны к применению. Их не просто так «захватили с собой» в javascript.

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

Людям, не спосбоным корректно распарсить *ptr++, нет смысла читать рабочий код. Им надо читать (и писать!) учебные примеры.

(а унарные и тринарные операции — это частный случай мудрённых конструкций).

Тем, для кого такие конструкции «мудреные», лучше вообще никакой код не читать. И не писать.

А тебя за раздачу «плохих советов» в /d/ следует хорошенько выпороть.

Источник

Оцените статью