Название: Прелести исключений Отправлено: Igors от Март 28, 2015, 08:09 Добрый день
Не ловится исключение в совершенно безобидном коде Код Получаю SIGABORT, отладчик выбрасывает меня в совершенно посторонний исходник. Мои действия - поменял исключение (что выбрасывает MyClass) на std::runtime_error. Ничего не изменилось - делаю throw первым в конструкторе MyCass - тот же вылет - вставил throw перед new - все норм, так ловится - заменил MyClass на свой (так же с throw в конструкторе) - все норм, так ловится - пошел по шагам в ассемблере - следы теряются на вызове throw Выдрать MyClass в тестовый пример не удается, он завязан на кучу других, поэтому "код в студию" не получится. Что можно предпринять? Спасибо Название: Re: Прелести исключений Отправлено: kamre от Март 28, 2015, 12:56 Может быть такое: во время выброса исключения из конструктора MyClass происходит вызов деструкторов для уже созданных его членов, и происходит выброс исключения из деструктора какого-то члена класса MyClass?
Название: Re: Прелести исключений Отправлено: _Bers от Март 28, 2015, 15:54 Добрый день Не ловится исключение в совершенно безобидном коде Код Получаю SIGABORT, отладчик выбрасывает меня в совершенно посторонний исходник. Мои действия - поменял исключение (что выбрасывает MyClass) на std::runtime_error. Ничего не изменилось - делаю throw первым в конструкторе MyCass - тот же вылет - вставил throw перед new - все норм, так ловится - заменил MyClass на свой (так же с throw в конструкторе) - все норм, так ловится - пошел по шагам в ассемблере - следы теряются на вызове throw Выдрать MyClass в тестовый пример не удается, он завязан на кучу других, поэтому "код в студию" не получится. Что можно предпринять? Спасибо код вовсе не безобидный, как вы думаете. рассмотрим пример: Код: #include <iostream> вывод: Цитировать Hello, world! address = 0 Что произошло: 1. new-expression сначала выделила память под объект. затем выполнила запуск конструктора класс. 2. из конструктора полетело исключение. не был вызван диструктор недостроенного объекта. вся выделенная память вернулась системе принимающий указатель остался без изменений. таким образом, значение ptr не изменилось. по сути: как будто бы ничего и не произошло. операция провалилась и произошел откат к первоначальному состоянию. что происходит в вашем случае: Код: try { ваш код выполняет неправомерную попытку удаления чужой памяти. Название: Re: Прелести исключений Отправлено: Igors от Март 28, 2015, 16:54 Может быть такое: во время выброса исключения из конструктора MyClass происходит вызов деструкторов для уже созданных его членов, и происходит выброс исключения из деструктора какого-то члена класса MyClass? Смотрел, там только POD члены - ну и сам он наследник QImage. А главное - деструктор не вызывается зовется исключением если оно выброшено из конструктора. что происходит в вашем случае: Ну программист который писал это в 90-х (старый код) конечно занулил указатель еще до try, поэтому здесь утечка (и то не на всех компиляторах). И входа в catch не происходит, ставил и печать перед delete и DebugStr - получаю SIGABORT точно "до того".Код: // вот здесь вы пытаетесь удалить память, которая не была выделена После неск часов метаний пришла мысля - просто сменил компилятор для этого файла (icc на сlang) . Все работает :) Еще неск часов - и нашел icc опцию которая гадила. Потом все-таки убрал throw из конструктора - ни к чему оно там, да и утечка. И все бы ничего если бы не много потерянных часов :'( Название: Re: Прелести исключений Отправлено: _Bers от Март 28, 2015, 20:18 Ну программист который писал это в 90-х (старый код) конечно занулил указатель еще до try, поэтому здесь утечка (и то не на всех компиляторах). какая ещё утечка? там не может быть утечеки. Еще неск часов - и нашел icc опцию которая гадила. в будущем, кто-то столкнется спободной проблемой. будет гуглить. наткнется на эту тему. и это все, что он узнает: "есть какая то опция". Название: Re: Прелести исключений Отправлено: Igors от Март 29, 2015, 08:27 какая ещё утечка? там не может быть утечеки. ПростаяКод Компилятор может установить значение data.ref после выделения блока памяти но еще до выполнения конструктора. Но может и нет, более того, такая установка - капитальный геморрой с multi-threadng. Некоторые имеют опцию (как-то со словом new, точно не помню), другие (напр icc) просто этого не делают. Не исключено что новом стандарте это запрещено. Поэтому последующее delete (в catch) до выделенного блока не дотянется. Название: Re: Прелести исключений Отправлено: _Bers от Март 29, 2015, 10:10 какая ещё утечка? там не может быть утечеки. ПростаяКод Компилятор может установить значение data.ref после выделения блока памяти но еще до выполнения конструктора. Но может и нет, более того, такая установка - капитальный геморрой с multi-threadng. Некоторые имеют опцию (как-то со словом new, точно не помню), другие (напр icc) просто этого не делают. Не исключено что новом стандарте это запрещено. Поэтому последующее delete (в catch) до выделенного блока не дотянется. память выделяется до запуска конструктора. если конструктор бросит исключение, то вся память будет возвращена системе. никаких утечек. если указатель был объявлен до секции try, то он останется без изменений. если в секции try, то будучи автоматическим объектом прекратит существование. причем тут multi-threadng я вообще не понял. но однозначно, он не имеет никакого отношения ни к эксепшенам, ни к операции выделения памяти. Название: Re: Прелести исключений Отправлено: Igors от Март 29, 2015, 10:23 если конструктор бросит исключение, то вся память будет возвращена системе. Первый раз слышу. Покажите где это написано. Спасибопричем тут multi-threadng я вообще не понял. ПримерКод Это неверно с 2 и более нитками по той причине что (во всяком случае в старом стандарте) не запрещается присвоить значение mInstance до того как конструктор отработал. Название: Re: Прелести исключений Отправлено: _Bers от Март 29, 2015, 11:43 если конструктор бросит исключение, то вся память будет возвращена системе. Первый раз слышу. Покажите где это написано. СпасибоЗдрасти, приехали. Вообще то об этом пишется во всех книжках для новичков. А выше я вам привел рабочий пример-иллюстрацию, который показывает, что после исключения указатель не изменился Цитировать 5.3.4 New [expr.new] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf20. If any part of the object initialization described above (78) terminates by throwing an exception, storage has been obtained for the object, and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression 78) This may include evaluating a new-initializer and/or calling a constructor. Совершенно очевидно, что сделано это по одной простой причине: Вы имеете полное право написать код: Код: try Если бы стандарт с++ не предусмотрел бы зачистку памяти в случае эксепшенов, то безопасное программирование на языке с++ превратилось бы в лютый ад. Пришлось бы кучу всего нужного выносить за блок try, что бы оно смогло выжить после его внезапного завершения. И тем самым бы нарушилось фундаментальное: "можно объявлять переменные по месту использования". с++ это вам не паскаль, где все переменные обязательно нужно объявлять в начале блока. Пример Понял. Надеюсь, вы осознаете, что это касается любых ситуаций чтения/записи в разделяемые несколькими потоками данные. Не является спецификой операции выделения памяти, и не имеет к этому отношения. Название: Re: Прелести исключений Отправлено: Igors от Март 29, 2015, 13:04 Здрасти, приехали. Ну если так, то почему Вы (и никто другой) не указал на эту ошибку сразу же? :) Вообще то об этом пишется во всех книжках для новичков. Да, проверил на примере, освобождает. Все же заметим что старый стандарт дает др формулировку (тот же 5.3.4) Цитировать If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function Тут я явно отсталНадеюсь, вы осознаете, ... Ой :)Название: Re: Прелести исключений Отправлено: _Bers от Март 29, 2015, 22:05 Ну если так, то почему Вы (и никто другой) не указал на эту ошибку сразу же? :) см. моё самое первое вам сообщение. Да, проверил на примере, освобождает. Все же заметим что старый стандарт дает др формулировку (тот же 5.3.4) Цитировать If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function Тут я явно отсталда, там есть поправка: если функция освобождения будет найдена. однако, я не могу себе представить ситуацию, когда она может быть не найдена. единственное, что приходит в голову - проблема удаления неполных типов. но как это состыкуется с new мне не очевидно. а может быть это как то связанно с наследием прошлого. одно могу сказать точно - ни разу в жизни не сталкивался с ситуацией, когда после эксепшена память не была освобождена. и даже не слышал о таких случаях. Название: Re: Прелести исключений Отправлено: Igors от Март 30, 2015, 10:13 Далеко не первый случай когда поиск бага в исключениями отливается во много часов. Основная трудность - вырубается отладчик. Да, можно найти на каком испускании это случилось (впрочем тоже требует времени). Ну а дальше-то что? Прошагать "Unwind" в asm нереально. Вот с полгода назад был случай
- при испускании исключения "зависает". Краша нет, но все заморожено. Отладчик показывает недра OC, стека вызовов нет. Замена исключения на другое (напр std) - то же самое. Ваши действия? Конечно я спрашиваю не "найти причину", а "как бы Вы искали" (т.е. метод поиска) Название: Re: Прелести исключений Отправлено: Пантер от Март 30, 2015, 10:15 Байда с этими исключениями. Я как-то 3 дня потратил, чтобы найти место падения. Пришлось методом перебора по модулям отлавливать. :(
Название: Re: Прелести исключений Отправлено: _Bers от Март 30, 2015, 14:35 Ваши действия? если по уму: глянуть лог. кто первым зафиксировал неполадки. кто последний реагировал на неполадки. кроме того, можно отследить всю трассу (наподобие, как в языке java): поймали в main эксепшен, и через него узнали: где изначально произошла неполадка, какие и откуда вылетали эксепшены, кто их ловил, как реагировал, и тп. очень удобно, особенно если это не тривиальный чужой код. -------------------------------------------------------------- хотя у меня однажды была проблема: прилетал обычный int. не понятно откуда, не понятно почему. крушение по причине "никто не обработал". (функция main - часть фреймворка, который в компетенции вообще третьих людей, и мне нельзя было коммитить его изменения без согласования с ними) эксепшен вылетал откуда то из библиотек (там километры километров кода), которые хз в каких годах писали какие то люди, которые давно уже канули в лету. из чего лично я сделал вывод: все решает культура кода. если делать тяп-ляп, забив болт на команду, то потом команда может огребсти. если сразу делать по уму: никаких проблем, даже если код - чужой. Название: Re: Прелести исключений Отправлено: Igors от Март 30, 2015, 16:00 если по уму: глянуть лог. Конечно это было бы прекрасно, но откуда ж взять те лог и (особенно) трассу? Если б отладчик показал стек вызовов - так нету! :'(кто первым зафиксировал неполадки. кто последний реагировал на неполадки. кроме того, можно отследить всю трассу (наподобие, как в языке java): поймали в main эксепшен, и через него узнали: где изначально произошла неполадка, какие и откуда вылетали эксепшены, кто их ловил, как реагировал, и тп. очень удобно, особенно если это не тривиальный чужой код. В моем случае я допер что кто-то гадит в деструкторе при раскрутке. Ну сделал свой класс с печатью в деструкторе, натыкал его везде и так (с горем пополам) локализовал. Оказалось деструктор одного из классов повис на мутексе, вот такая милая шутка :) Название: Re: Прелести исключений Отправлено: Авварон от Март 30, 2015, 17:05 gdb: catch throw
Название: Re: Прелести исключений Отправлено: _Bers от Март 30, 2015, 17:19 Конечно это было бы прекрасно, но откуда ж взять те лог и (особенно) трассу? Если б отладчик показал стек вызовов - так нету! :'( ну почему у них есть, а у вас нету? потому что они сделали для себя удобный инструмент, а вы не сделали. идешки кстати (ну по крайней мере вижал студия 2013 точно) умеют пасти стек вызовов: точки, где вылетают эксепшены. Название: Re: Прелести исключений Отправлено: Igors от Март 30, 2015, 17:32 ну почему у них есть, а у вас нету? Не понял кто "они" и что сделали ???потому что они сделали для себя удобный инструмент, а вы не сделали. идешки кстати (ну по крайней мере вижал студия 2013 точно) умеют пасти стек вызовов: Моя практика (правда на MSVC 2012 ) этого не подтверждает. Может удастся приспособить "Sudden Terminate", есть такой тул. Заметим что если надо "изыскивать средства/утилиты" - то тем самым признается по меньшей мере "существование проблемы".точки, где вылетают эксепшены. gdb: catch throw Что "catch throw" - это нужно где-то набирать? Название: Re: Прелести исключений Отправлено: Авварон от Март 30, 2015, 17:56 Что "catch throw" - это нужно где-то набирать? Да, набирать: https://sourceware.org/gdb/onlinedocs/gdb/Set-Catchpoints.html Ну или в Среаторе в окошке "Команды при подключении" Название: Re: Прелести исключений Отправлено: Igors от Март 31, 2015, 19:41 Ладно, попробуем тулзами. Вернул сбойную ситуацию, запустил "Sudden Terminate". Получил стек (первый аттач), привожу "содержательную часть" - трассу после вызова std::runtime_error. Я могу посмотреть код каждого вызова (второй и третий аттач). Хмм... ну и как это осмыслить? Не вижу откуда пришли на третий скриншот
То що це воно дало? :) Название: Re: Прелести исключений Отправлено: Igors от Апрель 01, 2015, 09:27 Да, набирать: Любовь с командной строкой в очередной раз не сложилась https://sourceware.org/gdb/onlinedocs/gdb/Set-Catchpoints.html Ну или в Среаторе в окошке "Команды при подключении" Цитировать (gdb) catch throw И дальше тот же вылет без всяких остановов. Где же я мог ошибиться набирая catch throw? Можно дать доп опцию (тип исключения) - но мне это не нужно. Какой "syntax error"? В общем, стандартный рез-т когда я начинаю чего-то "набирать" :)Catchpoint 5 (throw) A syntax error in expression, near `throw'.(gdb) catch throw (gdb) c Continuing. Название: Re: Прелести исключений Отправлено: Авварон от Апрель 01, 2015, 11:53 Да, набирать: Любовь с командной строкой в очередной раз не сложилась https://sourceware.org/gdb/onlinedocs/gdb/Set-Catchpoints.html Ну или в Среаторе в окошке "Команды при подключении" Цитировать (gdb) catch throw И дальше тот же вылет без всяких остановов. Где же я мог ошибиться набирая catch throw? Можно дать доп опцию (тип исключения) - но мне это не нужно. Какой "syntax error"? В общем, стандартный рез-т когда я начинаю чего-то "набирать" :)Catchpoint 5 (throw) A syntax error in expression, near `throw'.(gdb) catch throw (gdb) c Continuing. lldb попробуйте, gcc на маке древний как г. мамонта Название: Re: Прелести исключений Отправлено: Akon от Апрель 02, 2015, 23:02 Код: try { Если MyClass выбросит исключение, то data.ref не изменится, а память освободится (разумеется, в любых деструкторах исключения не допустимы). Посмотрите в какие ассемблерные инструкции ассемблируется new MyClass(id, type). Неотлов исключений связан с несовместимостью ABI, runtime. Отладка исключений: MSVC IDE с давних времен, например, выдает что-то типа first chance exception, т.е. отладчик может остановиться сразу, еще до первого обработчика. Название: Re: Прелести исключений Отправлено: Igors от Апрель 03, 2015, 09:29 Что это за код? Смысл использования исключений т.о? Не думаю что все так уж ясно. То что указатель data.ref может быть установлен еще до окончания конструктора - это жевалось много раз на форумах, и я видел даже опцию компилятора что этому посвящена. Если MyClass выбросит исключение, то data.ref не изменится, а память освободится (разумеется, в любых деструкторах исключения не допустимы). Посмотрите в какие ассемблерные инструкции ассемблируется new MyClass(id, type). Неотлов исключений связан с несовместимостью ABI, runtime. Отладка исключений: MSVC IDE с давних времен, например, выдает что-то типа first chance exception, т.е. отладчик может остановиться сразу, еще до первого обработчика. Смотреть код new MyClass - ну а что мы там хотим увидеть? Найти выброс исключения можно и средствами MSVC и руками, напр поставив DebugStr перед исключением в конструкторе. Так что с того? Это не объясняет почему не ловится. Давно заместил что "несовместимость ABI" - это просто то что "тыкается в нос" :) Почему сотни других (таких же) исключений ловятся как положено, а это нет? В первом же посте я писал про попытку воспроизвести ситуацию со своим классом. Что, ABI уже стало совместимо? :) В общем меня разочаровал Ваш ответ - типичный выброс заученных знаний, и ничего более Название: Re: Прелести исключений Отправлено: Akon от Апрель 03, 2015, 11:57 Ну так вы и смотрите в корень (читай в ассеблерный код), а разные форумы и т.п. жуйте в 3-ю очередь. Там же все будет как на ладони - установится data.ref или нет, освободится память или нет, как выглядит try/catch фрейм. Поверьте, более ясного источника нет. Вот если вы видите, что что-то не так, тогда ищите контролирующие опции компилятора.
Про ABI: возможно, ваш класс в свою очередь создает другие классы, которые в свою очередь скомпилированы с другими опциями или вовсе другим компилятором (например, это сторонняя библиотека), в результате чего нарушается ABI, попросту выброшенное исключение из библиотечного класса не ловится catch фреймом в вашем коде. Цитировать В общем меня разочаровал Ваш ответ - типичный выброс заученных знаний, и ничего более Нет проблем. Вы хотите, чтобы я не давал вам более подобного рода ответы?Название: Re: Прелести исключений Отправлено: Авварон от Апрель 03, 2015, 12:05 Не думаю что все так уж ясно. То что указатель data.ref может быть установлен еще до окончания конструктора - это жевалось много раз на форумах, и я видел даже опцию компилятора что этому посвящена. Смотреть код new MyClass - ну а что мы там хотим увидеть? Найти выброс исключения можно и средствами MSVC и руками, напр поставив DebugStr перед исключением в конструкторе. Так что с того? Это не объясняет почему не ловится. Давно заместил что "несовместимость ABI" - это просто то что "тыкается в нос" :) Почему сотни других (таких же) исключений ловятся как положено, а это нет? В первом же посте я писал про попытку воспроизвести ситуацию со своим классом. Что, ABI уже стало совместимо? :) В общем меня разочаровал Ваш ответ - типичный выброс заученных знаний, и ничего более Определитесь для начала с платформой. У вас мак? Вы уверены, что исключение вообще вылетает, а не, скажем, приходит сигнал? Вы пробовали lldb? (у меня на маке гдб нету вообще, так что я не могу проверить есть там catch throw или нет) Название: Re: Прелести исключений Отправлено: Igors от Апрель 03, 2015, 12:41 Ну так вы и смотрите в корень (читай в ассеблерный код), Об этом я тоже сказал в первом посте. До выброса исключения - все норм, вот правда почему-то отладчик не останавливается на std::runtime_error. Ну не беда, я могу поставить DebugStr перед ней и остановиться. Дальше надо идти внутрь исключения в asm - ну там не прорваться. Какие еще варианты?Смотреть класс/ABI, ну класс унаследован от QImage, "свои" только простые POD члены. Первое что сделал - "списал" его дав новое имя (выкинул все кроме конструктора) - с таким все ловится. Здесь тоже "дубль-пусто" Нет проблем. Вы хотите, чтобы я не давал вам более подобного рода ответы? Вовсе нет, просто от Вас я ожидал большегоОпределитесь для начала с платформой. У вас мак? Вы уверены, что исключение вообще вылетает, а не, скажем, приходит сигнал? Вы пробовали lldb? (у меня на маке гдб нету вообще, так что я не могу проверить есть там catch throw или нет) Так на lldb этой фишки (catch throw) просто нету. А gdb 2013 года - не новье, но и не такой уж старый.Баг (сам по себе) давно найден и устранен, но 2 дня коту под хвост. И это не первый такой случай. Вот и хочу на этом примере поизучать чтобы в след раз не сидеть днями. Название: Re: Прелести исключений Отправлено: Авварон от Апрель 03, 2015, 12:54 Так на lldb этой фишки (catch throw) просто нету. А gdb 2013 года - не новье, но и не такой уж старый. Баг (сам по себе) давно найден и устранен, но 2 дня коту под хвост. И это не первый такой случай. Вот и хочу на этом примере поизучать чтобы в след раз не сидеть днями. И верно, нету - http://stackoverflow.com/questions/8122375/lldb-breakpoint-on-exceptions-equivalent-of-gdbs-catch-throw Название: Re: Прелести исключений Отправлено: Igors от Апрель 03, 2015, 17:17 Попробовал с lldb (break set -E c++), да, работает. Но это всего лишь останов на точке испускания исключения. Полезная команда, но не помогает найти почему не пришло в catch
|