Привет всем.
Несколько дней назад попросили разобраться в коде некой программы (программа куплена с исходниками, даже есть некоторая поддержка со стороны разработчиков). Симптомы — запускаем программу, закрываем. ГУИ уходит, а вот программа остается висеть в памяти. И каждый новый запуск создает очередную копию, которая только из списка задач убивается

.
Беру исходники, ProcessExplorer, компилирую, запускаю на тестовой системе — ОК. Закрываю. Запускаю еще раз — в ProcessExplorer — 2 копии программы. Еще раз запускаю — 3 копии.
Оказалось, что при закрытии определенного фрейма вылетает AV. Вот тут и начались чудеса. Разработчики видимо решили не пугать пользователя и вынесли закрытие фреймов в процедуру типа:
Procedure FreeFrame(AFrame:TFrame);
begin
if Assigned(AFrame) then
try
FreeAndNil(AFrame)
except end; // <- фокус первый - тут всегда все тихо!
end;
Ладно, открываю проблемный фрейм и пробую закрыть — AV! Еще одна попытка — "Privileged instruction bla-bla". Интересно? Обычно AV он и в Африке AV — а тут без каких либо правок — 2 разных эксепшена + Call stack указывает в небо. Идем дальше — анализируем деструкторы фреймов — ВСЕ ПРАВИЛЬНО

. Все действительно корректно и должно разрушаться нормально. 2 часа дебага — и ничего — все корректно разрушается, но при закрытии фрейма всегда AV. И тут (в 2 часа ночи!) потянуло меня посмотреть, каким же образом фрейм этот создается...
Код был примерно такой:
case AFrameType of
fTypeOne : Frame:=TOneFrame.Create(...);
fTypeTwo : Frame:=TTwoFrame.Create(...);
.....
else : Frame:=TBaseTypeFrame.Create(...) ; // <- фокус второй - а давай-те хоть что-нить создадим, а?
end;
и далее:
case AFrameType of
......
fTypeNNN : TNNNFrame(Frame).SubFrame:=TSubFrame.Create(...); // уже догадались? Тут псевдокод, в реальном проекте тут разные свойства выставлялись.
......
end;
Так вот, разработчики в первом case (создания фреймов) пропустили один из fTypeХХХХ и создали какой-то свой базовый фрейм. СПАСИБО! Ну кто мешал в nil выставить? Во втором case они этот fTypeXXXX не забыли и благодаря приведению типов смогли угнездить туда (ага, именно куда-то туда — где-то рядышком) еще один фрейм, который нормально работал. До попытки закрытия

При закрытии деструктор лез непонятно куда и пытался что-то разрушить. Ну а благодаря некоторым манипуляциям вроде первой приведенной процедуры программа просто не могла нормально завершить свою работу.
Вывод — если уж пользуетесь приведением типов — делайте это в презервативе...
P.S. Процедуру создания фреймов я исправил, разработчиков известил (ну нет у меня времени выискивать все их пасхальные яйца). Жду новых оригинальных решений.
Здравствуйте, DarkMaster, Вы писали:
DM> Я не против try...except. Я против "глухого" срабатывания. Если произошло исключение — будь добр сообщить пользователю или по крайней мере запиши в лог, если исключение не ожидаемое. (Как меня бесило в свое время "Connection closed gracefully" в Indy — кто б знал!).
Ну, исключения не всегда являются ошибками. А по Инди есть книжица (Глубины Indy), где объясняется почему именно так, а не иначе
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, DarkMaster, Вы писали:
DM>> Я не против try...except. Я против "глухого" срабатывания. Если произошло исключение — будь добр сообщить пользователю или по крайней мере запиши в лог, если исключение не ожидаемое. (Как меня бесило в свое время "Connection closed gracefully" в Indy — кто б знал!).
H>Ну, исключения не всегда являются ошибками. А по Инди есть книжица (Глубины Indy), где объясняется почему именно так, а не иначе
Ну я же сказал — "....если не являются ожидаемыми". Обьясняется, согласен. Но бесит
Здравствуйте, DarkMaster, Вы писали:
[..]
Улыбнуло

А я познакомился с таким вариантом дизайна: из математической (!) процедуры программно нажимаются 3-и невидимые кнопки на форме, в обработчиках которых чё-то делается