Exceptionally Bad Exception Abuse — The Podcast at Delphi.org
Прошлой ночью я снова читал книгу Ника Ходжеса «Программирование в Delphi» (бессонница). В главе 1, посвященной обработке исключений , он начинает рассказ о том, как , а не , использовать исключения. Это заставило меня задуматься о некоторых ужасных случаях использования исключений, которые я видел. Я думал, что поделюсь несколькими примерами помимо обычных грехов-исключений.
Проба/Исключение/Поднятие/Свободный шаблон
Документация по 9Шаблон 0011 Try / Except говорит, что весь код после блока Except запускается, поскольку исключение обрабатывается. Кроме того, вы можете вызвать Raise во время обработчика, чтобы отправить исключение дальше по стеку вызовов.
Я только что устроился на новую работу и сидел с одним из старших разработчиков , исправлял некоторые ошибки и знакомился с кодовой базой. Он создавал локальный объект и поэтому должен был его освободить. Вот шаблон, который он использовал:
sl := TStringList.Create; пытаться // используя сл кроме поднимать; конец; сл.Свободный;
С минуту я недоуменно смотрел на код, а потом спросил, зачем он это сделал. Он объяснил, что все после , кроме , всегда запускается, поэтому он может быть уверен, что память освобождена, но все же позволяет исключению подняться до глобального обработчика исключений, чтобы оно было зарегистрировано. Я сказал ему, что я почти уверен, что вызов
Я еще немного подумал и предложил протестировать код. Итак, мы сделали небольшое тестовое приложение с сообщением после блока , кроме , и заставили его вызвать исключение, и, конечно же, сообщение не отображалось. (Всегда проверяйте свои теории и закономерности с помощью тестового кода!)
На его лице отразилась паника. Он использовал этот шаблон в течение 90 003 лет 90 004 , и он применялся во всех кодовых базах. Он утверждал, что документация, должно быть, неверна или она изменилась в недавнем обновлении, но я пытался заверить его, что это было ясно и всегда работало именно так, он просто неправильно понял.
Зарегистрируйте их все и позвольте службе поддержки разобраться с ними
Это использовалась ранняя версия C# и WinForms.NET в Visual Studio. Я взялся за проект и с трудом отслеживал какое-то странное поведение. Какой-то код просто не запускался, и сообщений об ошибках не было. Это был проект, который был очень, очень рано в процессе разработки, и мой первый крупномасштабный проект на C#, и я очень расстраивался.
Наконец-то я обнаружил, что возникало исключение, но оно никогда не отображалось как ошибка. Даже если отладчик был подключен, сообщения об исключении не было. Программа просто продолжала работать, как будто ничего не произошло, но операция прерывается. Я начал сомневаться в способности . NET обрабатывать исключения.
Я копался, копался и, наконец, выяснил, что предыдущий разработчик настроил глобальную систему обработки и регистрации исключений, которая собирала все исключения и записывала их в возможную базу данных поддержки с подробным стеком вызовов. Приложения IIRC WinForms закрываются автоматически, если возникает необработанное исключение, поэтому иметь обработчик исключений — хорошая идея, но их молчаливая регистрация кажется сомнительной. А затем, поскольку существовала система регистрации исключений, разработчик установил параметры проекта, чтобы отладчик игнорировал все исключения.
В результате приложение работает без исключений даже во время разработки, но, по крайней мере, поддержка будет иметь много отладочной информации. Я поговорил с первоначальным разработчиком, и он подумал, что это блестящая идея, и сказал, что это первое, что он делает во всех своих проектах. Он просто просматривает базу данных поддержки, чтобы убедиться, что все работает. Его логика заключается в том, что пользователи не хотят видеть сообщения об ошибках. Не уверен, что скрытие всех сообщений об ошибках — хорошая идея, особенно скрытие их от разработчика во время разработки.
Исключения как надежные возвращаемые объекты
Я поддерживал некоторый код, в котором предыдущий разработчик построил эту систему, в которой для возврата сложной системы типов использовались специальные исключения. Он построил эту впечатляющую иерархию классов исключений, а затем обрабатывались только определенные типы исключений на разных уровнях, где данные были необходимы. Таким образом, вместо того, чтобы методы возвращали результат или изменяли переданное значение, все они просто вызывали разные исключения со свойствами, установленными на разные значения.
На мой взгляд, здесь две проблемы. Во-первых, создание и обработка исключений довольно затратны. Лучшим вариантом было бы просто создать простые старые объекты (или даже интерфейсные объекты) и вернуть их в качестве результатов. Вы по-прежнему можете изучить их типы и решить, когда с ними работать. Вам просто нужно знать об управлении жизненным циклом объекта (автоматическая обработка жизненного цикла была его оправданием для использования исключений).
Вторая проблема заключается в том, что это была всего лишь одна подсистема более крупного проекта. Только эта подсистема использовала эту причудливую систему управления данными. Поэтому, когда вы исправляли здесь ошибку, у вас возникала умственная нагрузка, связанная с другой архитектурой. Как только вы во всем разберетесь, исправите ошибку и перейдете к другому коду, вы вернетесь к нормальному образу мыслей. Снова платите моральный налог за то, что забыли о злодеянии, свидетелем которого вы только что стали.
Я действительно считаю, что в большом проекте должна быть некоторая согласованность в том, как спроектированы части, если только нет веских причин делать что-то по-разному в одной подсистеме. Это облегчает разработчикам работу в разных частях системы.
Итак, какие самые безумные злоупотребления исключениями и их обработкой вы видели?
Кстати, у Ника вышла новая книга о внедрении зависимостей в Delphi. Вы должны забрать копию.
Исключения, возникающие в пользовательском сервере Delphi с приоритетом кода, вызывают нарушения прав доступа в клиентском приложении — Remoting SDK
Стюарткленнетт (Стюарт Кленнет) 1
Привет,
Я вызываю исключения на сервере, которые я хочу показать в клиенте, но независимо от того, что я делаю на сервере, я всегда получаю нарушение прав доступа или недопустимую операцию указателя на клиенте.
Delphi 10.3 / RO-DA 10.0.0.1495
Спасибо
EvgenyK (Евгений Карпов) 2
Привет,
Пожалуйста, ознакомьтесь с образцом MegaDemo. он показывает, как передать исключение со стороны сервера на сторону клиента.
1 Нравится
мч (Марк Хоффман) 7
Стюарт,
Стюарткленетт:Я вызываю исключения на сервере, которые я хочу отобразить в клиенте, но независимо от того, что я делаю на сервере, я всегда получаю сообщение о нарушении прав доступа или о недопустимой операции указателя на клиенте.
это должно «просто работать» из коробки, если что-то не пойдет не так или не испортит код исключения дерева. У вас есть стек вызовов для AV или IPO? Вы получаете одно или другое случайно, или в этом есть какая-то последовательность?
Ваш код добавляет что-то особенное, нестандартное в инфраструктуру RO, помимо простых вызовов (т.
е. пытается самостоятельно обработать какие-либо события OnException или тому подобное)?Стюарткленнетт (Стюарт Кленнет) 10
Привет, marc
Я возвращаюсь в RO/DA после года работы над другими проектами, и я подумал, что это «просто сработало». Я не делаю ничего, что я бы назвал особенным или нестандартным. Иногда я вызываю исключения в вызовах удаленных методов, надеясь, что они будут вызваны на клиенте. Но в основном я просто хочу видеть естественные исключения.
Я не видел шаблона AV против IPO… может быть, клиентское приложение VCL или нет?
Я получу трассировку стека на стороне клиента в понедельник
Спасибо
1 Нравится
мч (Марк Хоффман) 11
Стюарткленнет:Я получу трассировку стека на стороне клиента в понедельник
Я думаю, это может сильно помочь, да. Спасибо!
Стюарткленнетт (Стюарт Кленнет) 12
Я добавил очевидную ошибку в свой серверный метод, который вызывал «Индекс вне допустимого диапазона», а затем вызвал этот метод из консольного клиентского приложения, что привело к следующей активности на стороне клиента.
Проект aqDBUpgrade.exe поднял класс исключения EInsufficientRtti с сообщением «Недостаточно RTTI для поддержки этой операции».
…Нажмите BREAK…
:7743b922 KERNELBASE.RaiseException + 0x62
:0044c323 CheckCodeAddress + $13
:0046258b TRttiMethod. Invoke + $47
urRORTTISupport.TRORttiClientCache.RebuildCache
uRORTTISupport.TRORttiClientCache.GetExceptionClass(‘EAccessViolation’, $292B710)
uRORTTISupport.RORTTI_GetExceptionClass(‘EAccessViolation ‘,$292B710)
uROExceptions.GetExceptionClass(‘EAccessViolation’,$292B710)
uROMessage.TROMessage.CreateException(‘EAccessViolation’,’Нарушение прав доступа по адресу 01BC69F3 в модуле «AquilaServer.exe». Чтение адреса 00000000′)
uROBinMessage.TROBinMessage.ReadException
uROMessage.TROMessage.ProcessException
uROBinMessage.TROBinMessage.IntReadFromStream($28D8C00,False)
uROBinMessage.TROBinMessage.ReadFromStream($28D8C 00, False)
AquilaLibrary_Intf.TiBIDSvc_Proxy.DependencyCalcsDateRangeEx(-36887,2958465,False,$28FB168)
… Нажмите F9…
Проект aqDBUpgrade.exe поднял класс исключения EInvalidPointer с сообщением «Недопустимая операция указателя».
…Нажмите Break…
:00408af5 TObject.FreeInstance + $11
(это lMessage := nil
в разделе «Наконец» сгенерированного метода)
AquilaLibrary_Intf.TiBIDSvc_Proxy.DependencyCalcsDateRangeEx(-36887 ,2958465,False,$28FB168)
dmDBUpgraderData1.TdmDBUpgraderData.RecalcAnalysis(‘Ah48896008’,[])
…F9…
Проект aqDBUpgrade.exe поднял класс исключения EInvalidPointer с сообщением «Недопустимая операция указателя».
…нажмите Break…
:00408af5 TObject.FreeInstance + $11
:00408b33 TObject.Free + $B
:0040f2a3 @IntfClear + $13
uROInterfacedObject.TROInterfacedObject._Release
:0040f2a3 @IntfClear + $13
aqDBUpgrade. Main
Теперь это отображается на клиенте как «Недопустимая операция указателя».
Надеюсь, это поможет.
ЕвгенийК (Евгений Карпов) 13
Привет,
Согласно стеку вызовов, эта проблема является ошибкой в Remoting SDK.
Однако вы используете устаревшую версию RO, поэтому эта проблема, кажется, исправлена в течение последних 1,5 лет, потому что этот AV не воспроизводится с помощью простого тестового примера. testcase.zip (221,4 КБ)
Можно ли повторно протестировать проект с последней пробной версией Remoting SDK?
Стюарткленнетт (Стюарт Кленнет) 14
Привет, marc & Evgeny,
Странно, что вы говорите, что я использую устаревшую версию программного обеспечения, поскольку экран-заставка Remobjects и проверка версии при загрузке Delphi говорят, что все мои продукты обновлены?
Кроме того, я продлил свою лицензию 1 марта, но портал по-прежнему говорит, что мне нужно «Продлить сейчас, чтобы получить доступ к этой сборке», хотя в нем указано, что срок действия текущей лицензии не истекает до марта 2023 года. Он также показал пункт продления. в моей корзине, которую я сейчас удалил.
Последняя версия, которую я могу получить, это 10.0.0.1533.
Когда я запускаю экран приветствия Everwood и проверяю наличие обновлений, он ничего мне не говорит, когда я нажимаю «Обновить». Это после нажатия «Обновить»:
?? Не говорит, что все в курсе, но и не уведомляет меня о каких-либо новых выпусках?
Что-то пошло не так с обновлением — может ли кто-нибудь разобраться с этим для меня ??
Спасибо,
Стюарт
Для информации:
mh (Марк Хоффман) 16
Стюарткленнет:Также — я продлил свою лицензию 1 марта, но портал по-прежнему говорит, что мне нужно «Продлить сейчас, чтобы получить доступ к этой сборке», хотя в нем указано, что срок действия текущей лицензии не истекает до марта 2023 года.
Он также показал пункт продления в моя корзина, которую я сейчас удалил. Последняя версия, которую я могу получить, это 10.0.0.1533.
FWIW, лицензия в вашей учетной записи действует до марта 2023 года… Я посмотрю, если/почему вы не можете загрузить последнюю версию…
mh (Марк Хоффман) 17
мч:FWIW, лицензия в вашей учетной записи действует до марта 2023 года… Я посмотрю, если/почему вы не можете скачать последнюю версию…
У вас есть доступ только к версиям Delphi, но это ожидаемо и соответствует вашей лицензии, и загрузка проходит нормально?. Хотя я признаю, что не ожидал, что он покажет сообщение «Продлить сейчас», а просто должен увидеть другие выпуски — я проверю и исправлю, почему это происходит.
Стюарткленнетт (Стюарт Кленнет) 19
Привет, marc
Спасибо. Признаюсь, я даже не пытался скачать ссылку
Не могли бы вы разобраться, почему мой Everwood тоже сообщает, что все обновлено? Я просто нигде не вижу никаких уведомлений о новых выпусках, и я хотел бы оставаться в курсе.
Я попробую сборку 1533, посмотрим, решит ли это проблему.
Спасибо
мч (Марк Хоффман) 20
Стюарткленнет:Не могли бы вы разобраться, почему мой Everwood тоже сообщает, что все обновлено? Я просто нигде не вижу никаких уведомлений о новых выпусках, и я хотел бы оставаться в курсе.
@ЕвгенийК?
Стюарткленнет:Я попробую сборку 1533, посмотрим, решит ли это проблему.
сотрудничество, спасибо!
ЕвгенийК (Евгений Карпов) 21
Привет,
Стюарткленнет:Не могли бы вы разобраться, почему мой Everwood тоже сообщает, что все обновлено? Я просто нигде не вижу никаких уведомлений о новых выпусках, и я хотел бы оставаться в курсе.
это известная проблема (#337), которая была исправлена после выпуска версии .1495.
Стюарткленнетт (Стюарт Кленнет) 23
Привет, Евгений,
Вот что я сейчас получаю через Everwood (сборка 1533) — «Была проблема с проверкой обновлений»:
у меня все в курсе.
С наилучшими пожеланиями
EvgenyK (Евгений Карпов) 25
Привет,
Стюарткленнет:Когда я «нажимаю здесь, чтобы повторить попытку», открывается список версий, который говорит мне, что все обновлено.
странно, я не могу воспроизвести это:
возможно ли, что у вас проблемы с подключением к сети?
Стюарткленнетт (Стюарт Кленнет) 33
Привет,
Нет, интернет работает нормально
stuartclennett (Стюарт Кленнет) 35
Сборка 1533, кажется, решила мою проблему с передачей сообщений об ошибках клиенту — спасибо за это
mh (Марк Хоффман)