AV при генерации своего исключения

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

AV при генерации своего исключения

Сообщение Иван Шихалев » 08.06.2013 01:44:05

Ситуация такая — при некотором условии в методе генерируется (raise) исключение. Этот метод вызывается из другого, где он завернут в try ... finally, который в свою очередь вызывается из третьего, где завернут в try ... except. Но до блока finally управление не доходит — где-то возникает Access Violation. До raise доходит точно — проверено отладочным выводом.

Что интересно, если raise закомментировать и просто возвращать некое специфическое значение, всё проходит на ура, т.е. повреждений стека перед ним нет.

Локализовать в минимальном примере не получается. Закомментированная проблемная строка на гитхабе — вот.

Может быть, кто-то сталкивался уже с подобным — куда копать-то вообще?
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: AV при генерации своего исключения

Сообщение NTFS » 08.06.2013 10:47:30

При неожиданном поведении своего кода иногда срабатывает ПОЛНОЕ стирание всего, включая ОС, компилятор, библиотеки - и установка на чистую машину заново.

Еще, когда у меня начинали сыпаться в неизвестном месте AV или SIGSEGV, я выкидывал весь модуль и делал его заново - как правило, срабатывает.

Добавлено спустя 1 минуту 29 секунд:
Val2Str и Inspect - эти две функции смущают. Если их заменить на строковую константу, поведение изменится?
NTFS
постоялец
 
Сообщения: 388
Зарегистрирован: 05.11.2007 14:57:50
Откуда: Краснодар

Re: AV при генерации своего исключения

Сообщение Sergei I. Gorelkin » 08.06.2013 12:34:03

Внешняя работоспособность программы не означает, что стек не поврежден. Например, после того, как функция прочитала свои аргументы, область стека, где находились эти аргументы, можно перезаписать без последствий.

Берешь отладчик, определяешь, из-за чего возникло AV (скорее всего, на стеке окажется не то значение, которое там должно быть), после чего ставишь на этот адрес hardware breakpoint или watch, и оказываешься в нужном месте кода (перед этим побывав во всех местах, которые изменяют проблемный адрес легитимно).
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: AV при генерации своего исключения

Сообщение Иван Шихалев » 08.06.2013 12:35:17

NTFS писал(а):Еще, когда у меня начинали сыпаться в неизвестном месте AV или SIGSEGV, я выкидывал весь модуль и делал его заново - как правило, срабатывает.


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

NTFS писал(а):Val2Str и Inspect - эти две функции смущают. Если их заменить на строковую константу, поведение изменится?


Пробовал заменять на строковый литерал — не изменилось. Еще пробовал их результат помещать в переменную и выводить сначала WriteLn'ом — выводится, а на raise все тоже самое.
Я тоже на них думал, особенно на Val2Str, поскольку там преобразование внешнего PChar в строку происходит. Но без исключений оно работает.

Добавлено спустя 26 секунд:
Sergei I. Gorelkin писал(а):Берешь отладчик, определяешь, из-за чего возникло AV


А здесь можно поподробнее?

Добавлено спустя 7 минут 24 секунды:
Пока что отладчиком удалось установить только то, что AV происходит на выходе конструктора исключения, все, что до отрабатывается правильно (с виду).
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: AV при генерации своего исключения

Сообщение Sergei I. Gorelkin » 08.06.2013 13:38:38

Иван Шихалев писал(а):А здесь можно поподробнее?

Нужно определить инструкцию, на уровне ассемблера, на которой происходит AV, и посмотреть, к какому адресу памяти она обращается. Иногда приходится помучаться, особенно если имеет место, например, вызов виртуального метода уничтоженного объекта - тогда управление передается по левому адресу и стек вызовов не несет полезной информации.

Если AV происходит на выходе из конструктора исключения, при том что аргументом является строковый литерал, то тут подозрение падает больше не на стек, а на кучу.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: AV при генерации своего исключения

Сообщение Иван Шихалев » 08.06.2013 14:42:47

В общем, с raise подозрения снимаются — и без него повторная ошибка в ruby дает AV. Что забавно — между первой, которая не дает, и второй может быть сколько угодно успешных вызовов... При этом rb_eval_string_protect() работает в точности как полагается, но от нее пришлось отказаться, поскольку она свято уверена, что строка в US-ASCII, а параллельных вариантов, как для просто преобразования строк, с кодировками для нее не предусмотрено...

Добавлено спустя 39 минут 32 секунды:
Впрочем, с rb_eval_string_protect() тоже странно получается — вроде бы и все ок, никаких AV, вылетает только мое сгенерированное исключение... Но почему-то оно вылетает сразу на дефолтный обработчик с MessageBox'ом, а не перехватывается в try ... except...

Добавлено спустя 50 минут 8 секунд:
А не, сорри — там ловилось не то (иерархия исключений крива оказалась). rb_eval_string_protect() таки полностью правильно работает.

Добавлено спустя 1 час 34 минуты 15 секунд:
Вот еще что странно: попробовал везде заменить cdecl на stdcall (т.е. в объявлениях внешних фунций и своих, передаваемых во внешние). Не изменилось ничего, хотя, казалось бы должно посыпаться... Что-то я не понимаю, похоже.
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: AV при генерации своего исключения

Сообщение Sergei I. Gorelkin » 08.06.2013 22:45:40

Иван Шихалев писал(а):Вот еще что странно: попробовал везде заменить cdecl на stdcall (т.е. в объявлениях внешних фунций и своих, передаваемых во внешние). Не изменилось ничего, хотя, казалось бы должно посыпаться... Что-то я не понимаю, похоже.


Разница между stdcall и cdecl реально есть только на i386, на остальных платформах, действительно, может работать... пока речь не идет о переменном числе параметров.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: AV при генерации своего исключения

Сообщение Иван Шихалев » 08.06.2013 22:52:06

Sergei I. Gorelkin писал(а):Разница между stdcall и cdecl реально есть только на i386

Т.е. на других платформах стек очищает таки вызываемая подпрограмма? Но при переменном числе — вызывающая? Как-то все это сложно... Да, у меня x64.
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: AV при генерации своего исключения

Сообщение Sergei I. Gorelkin » 09.06.2013 01:58:23

Там нет очистки стека как таковой, используются т.н. фиксированные кадры стека, память для всех аргументов (по максимуму) выделяется на входе в вызывающую процедуру. С переменным числом параметров связаны всякие нюансы типа "число задействованных xmm регистров передается в регистре al" (это для x86_64-linux).
Кроме того, на уровне языка параметры типа "array of const" для cdecl-функций считаются "переменным числом параметров", а для остальных - как array of TVarRec известного размера.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: AV при генерации своего исключения

Сообщение Иван Шихалев » 09.06.2013 03:27:10

Мда, подотстал я от жизни... А где можно про все это поподробней почитать? Можно на английском...
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: AV при генерации своего исключения

Сообщение Sergei I. Gorelkin » 09.06.2013 04:35:31

Для Linux/BSD - спросить у гугля про "System V ABI", из результатов выбрать интересующий процессор :)
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: AV при генерации своего исключения

Сообщение Иван Шихалев » 19.11.2013 08:29:02

Проблема локализована. Правда, на гитхабе пока не пофиксил. При работе с чужеродными исключениями требуется:
Код: Выделить всё
{$IMPLICITEXCEPTIONS OFF}
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: AV при генерации своего исключения

Сообщение Sergei I. Gorelkin » 19.11.2013 18:29:53

Это маскирует проблему, но не устраняет ее. Свалится где-то в другом месте.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: AV при генерации своего исключения

Сообщение Иван Шихалев » 20.11.2013 03:15:50

Нет, это не маскирует. Суть проблемы в том, что ruby-исключения не должны возникать в try-контексте. А паскалевские, в свою очередь — в rb_protect.
Так вот, чтобы гарантировать отсутствие try, в некоторых местах нужно запретить его неявное создание. Да, само собой, в этих местах нельзя использовать динамические типы даже неявно (собственно, во всяких неявностях и была проблема).
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: AV при генерации своего исключения

Сообщение Sergei I. Gorelkin » 20.11.2013 13:01:52

Теперь до меня дошло, что речь о двух разных видах исключений: FPC vs. Ruby, причем последние еще и бросаются из другого исполняемого модуля (dll/so). Тогда да, неиспользование исключений является как бы решением...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 250

Рейтинг@Mail.ru