• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

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

    Запись на курс до 25 апреля. Получить промодоступ ...

Обработка ошибок

  • Автор темы Akupaka
  • Дата начала
T

turumbay

Исключение мы обработаем внутри. Но с помощью Err можно узнать номер ошибки после выхода из функции. И при желании вызвать еще одно исключение.
Короче, пример. В результате получим и 5, и обработаем ошибку.
по сути кода: исключение не генерица, при ошибке изменяем глобальную переменную, клиент проверяет эту глобальную переменную.
имхо - очень порочная практика: наличие неочевидных побочных эффектов - это зло. Почему клиенту надо помнить о необходимости проверки Err? Нужно ли клиенту сбрасывать код ошибки?
Если это приватный метод класса - то еще куда ни шло(но если увижу - перепишу :) ) . А для паблик функций - не годится.
Все же вроде просто: если дело швах и не можем справица в контексте функции - бросаем исключение - пусть вызывающий метод разбираеца. Если в состоянии справица сами(т.е. в контексте) - обрабатываем по месту так, чтобы никто ничего не узнал.
 
A

Akupaka

turumbay
Исключение и результат нужны тогда, когда это удобно ;) Это не должно быть правилом.
Как я писал в первом посте в примере. Иногда удобно затулить функцию в IF и в зависимости от результата выполнять некий код или нет.
Но, если в функции возникает необработанное исключение, то IF может выполнить неверное действие.
Пример кода:
Код:
Function F1() As Variant
F1 = False
Error 1000, "Some error"
End Function

Function F2() As Variant
F2 = False
Error 1000, "Some error"
End Function

Sub Initialize()
On Error Resume Next
' иногда удобно организовывать проверки каскадом такого вида
' но, при неудачном обработчике такой код будет выполняться неверно
If Not(F1()) Then
Msgbox "Проверка 1 неудачна"
ElseIf Not(F2()) Then
Msgbox "Проверка 2 неудачна"
Else
Msgbox "Все проверки удачны"
End If

End Sub

теперь, если добавить возврат ошибки, то можно нарисовать так

Код:
Function F1() As Variant
On Error Goto ERH
F1 = False
Error 1000, "Some error"
ERH:
Call SetErrorState(...)
F1 = False
Exit Function
End Function

Function F2() As Variant
F2 = False
Error 1000, "Some error"
End Function

Sub Initialize()
On Error Resume Next
' иногда удобно организовывать проверки каскадом такого вида
' но, при неудачном обработчике такой код будет выполняться неверно
If Not(F1()) Then
Msgbox "Проверка 1 неудачна в следствие ошибки " & GetErrorText(...)
ElseIf Not(F2()) Then
Msgbox "Проверка 2 неудачна"
Else
Msgbox "Все проверки удачны"
End If

End Sub

Этот возврат можно сделать очень по-разному. Это может быть параметр вызываемых функций, это может быть внутренний глобальный объект, как удобно.
И ничего порочного нет, если использовать правильно :)

Почему клиенту надо помнить о необходимости проверки Err? Нужно ли клиенту сбрасывать код ошибки?
Можно сделать так, чтобы это было необязательным!
С таким же успехом я могу воскликнуть: "А зачем клиенту помнить о необходимости правильного обработчика?!"
Функция молча возвращает неуспешный результат! А не непредсказуемый. И программист может эго использовать при необходимости.
 
N

nvyush

Akupaka
Всё, конечно, от ситуации зависит, но в приведённом примере я вижу настойчивое желание использовать On Error Resume Next и сетовать, что If не правильно отрабатывает. Думаю, что лучше всё-таки использовать On Error Goto ERH и уже в обработчике определять где и какая ошибка возникла.



Добавлено:
Функция молча возвращает неуспешный результат! А не непредсказуемый. И программист может эго использовать при необходимости.
В WinAPI встречается такое — прежде чем использовать результат функции, нужно проверить, не возникла ли ошибка. Но, честно говоря, никогда не сталкивался с необходимостью такого подхода при программировании на ЛС.
 
A

Akupaka

Всё, конечно, от ситуации зависит, но в приведённом примере я вижу настойчивое желание использовать On Error Resume Next и сетовать, что If не правильно отрабатывает
Я не сетую, что он неправильно работает ;) Я говорю, что некоторые конструкции выполняются некорректно, при подобном подходе, а иногда его использовать удобнее.
 
T

turumbay

Исключение и результат нужны тогда, когда это удобно :) Это не должно быть правилом.
Да не может быть это удобно никогда. Реальный пример в студию!
Как я писал в первом посте в примере. Иногда удобно затулить функцию в IF и в зависимости от результата выполнять некий код или нет.
Желание нормальное. Вот код из упомянуго шаблона discussion
Код:
Private Function HasUI As Boolean
On Error Goto ERROR_HANDLER
Dim oUIWorkspace As New NotesUIWorkspace
HasUI = True
Exit Function
ERROR_HANDLER:
Err = 0
Exit Function
End Function
Все четко и ясно. Функция делает ровно то, что от нее ожидается. То что внутре генерица исключение - никто кроме нее не знает.
Но, если в функции возникает необработанное исключение, то IF может выполнить неверное действие.
Это может произойти ТОЛЬКО в случае resume next - т.е. когда вы намеренно игнорируете исключение. Вывод очевиден - не использовать resume next без крайней нужды.
А у вас вызывающий код знает особенности реализации вызываемой функции. А ему этого знать не положено!

В WinAPI встречается такое — прежде чем использовать результат функции, нужно проверить, не возникла ли ошибка.
Это так только потому, что в си нету исключений. Так что конструкция эта - вынужденная.
 
A

Akupaka

А у вас вызывающий код знает особенности реализации вызываемой функции. А ему этого знать не положено!
Это почему, если это мои два класса и они между собой связаны? О.о ))
Не надо чесать все одной расческой ;)
Это может произойти ТОЛЬКО в случае resume next - т.е. когда вы намеренно игнорируете исключение
Нет, ну это ж надо быть таким упрямым :) Я же говорю, что мне иногда это удобнее использовать.
Реальный пример в студию!
Пример был выше в 22-м посте. Между прочим, он был адресован тебе :)

Все четко и ясно. Функция делает ровно то, что от нее ожидается. То что внутре генерица исключение - никто кроме нее не знает
Дык, у меня тоже четко и ясно, и никто выше не знает, что в вызываемой функции было исключение :(
Но кроме результата, что функция выполнилась неудачно, есть еще код ошибки.
 
O

OlegSmirnov

Хорошая тема, Akupaka!

Я делаю таким образом:
1. есть либа, а точнее функция, которая обрабатывает ошибки в скриптах
2. при написании кода юзаем ее с параметрами

Подробнее:

Либа:
Код:
Option Public
Option Declare

%REM
<information>
<description>
Библиотека для обработки ошибок в скриптах
</description>

<input params>
...
</input params>

<output params>
...
</output params>

<result>
...
</result>

<others>
Пример вызова ProcessError:
Call ProcessError (LIB_NAME, Err, Error, Erl, Lsi_info (2), Lsi_info (12))
</others>
</information>
%END REM
Private Const MODULE_NAME = "Библиотека <libError>"

Function ProcessError (moduleName As String, errNum As Variant, errDescr As Variant, _
errLine As Integer, errorPlace As String, callBy As String)
%REM
<information>
<description>
Функция обрабатывает ошибку
</description>

<input params>
moduleName - имя модуля, в котором произошла ошибка
errNum - номер ошибки
errDescr - описание ошибки
errLine - строка, в которой произошла ошибка
errorPlace - имя функции, в которой возникла ошибка
callBy - имя функции, которая вызвала, функцию, в которой возникла ошибка
</input params>

<output params>
...
</output params>

<result>
True - процесс обработки ошибки завершен удачно
False - во время обработки ошибки возникли ошибки
</result>

<others>
...
</others>
</information>
%END REM

On Error Goto errorHandler

Dim session As New NotesSession

Dim db As NotesDatabase

Dim logA As cscLOG

Print moduleName , errorPlace & " called by " & callBy , "ошибка № " & errNum & ": " & errDescr & " (line: " & Cstr (errLine) & ")"

Msgbox moduleName & "." & Chr (13) & _
"Функция " & errorPlace & " called by " & callBy & "." & Chr (13) &_
"Ошибка № " & errNum & ": " & errDescr & " (line: " & Cstr (errLine) & ").", 16, "Ошибка"	

Set db = session.CurrentDatabase

Set logA = New cscLOG

Call logA.AppendText (LOG_ITEM_TYPE_ERROR, LOG_ACTION_TYPE_ERROR, "бд: " & db.Title & " (Сервер = " & db.Server & ", путь = " & db.FilePath & "), модуль: " & moduleName & ", " & errorPlace & " called by " & callBy & ". Ошибка № " & errNum & ": " & errDescr & " (line: " & Cstr (errLine) & ")")

ex:
Exit Function

errorHandler:
Print MODULE_NAME , Lsi_info (2) & " called by " & Lsi_info (12) , "ошибка № " & Err & ": " & Error$ & " (line: " & Cstr (Erl) & ")"

Msgbox "Библиотека " & MODULE_NAME & "." & Chr (13) & _
"Функция " & Lsi_info (2) & " called by " & Lsi_info (12) & "." & Chr (13) &_
"Ошибка № " & Cstr (Err) & ": " & Error$ & " (line: " & Cstr (Erl) & ").", 16, "Ошибка"

Resume ex			
End Function

Использование:
Код:
...

ex:
Exit Function

errorHandler:
Call ProcessError (MODULE_NAME, Err, Error, Erl, Lsi_info (2), Lsi_info (12))
Resume ex
End Function

Хорошо бы еще доработать со временем код. Как вариант можно добавить версию кода, вроде:
Код:
Private Const MODULE_NAME = "Библиотека <libError>"
Private Const VERSION_NAME = "1.0.0"

Akupaka, надеюсь то :gifts:
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
В библиотеках обработчик ошибки возвращает ошибку наверх, а вот в кнопках и событиях ошибки обрабатываются и логируются. В результате всегда (почти) можно посмотреть, откуда у ошибки "ноги растут".
Я делаю почти также. Идея была где-то . И с lsi_info, ничего не вылетает.
 
T

turumbay

1. есть либа, а точнее функция, которая обрабатывает ошибки в скриптах
понимаю, что код не ваш, но т.к. автор не указан - спрошу у вас:
что делает приведенная функция? это пример использования on error goto?
- почему print+msgbox не оформлено в виде отдельной процедуры для устранения дублирования в теле функции и в обработчике ошибок?
- зачем у этой функции errhandle? очевидно, что ошибка может возникнуть только внутри класса cscLOG. Почему класс не в состоянии обработать ее самостоятельно?
- зачем собсно одновременно используется print и msgbox?
- у Err и Error глобальная область видимости, зачем передавать их в обработчик?
- почему не сбрасывается err?
- что делать, если надо передать ошибку в вызывающую функцию( т.е. где возможность передачи вверх по стеку вызовов) ?
З.Ы. Чем вызвано использование "псевдо XML" для документирования? Есть какая-нить хитрая тулза для построения документации?
Почему используются тэги, содержащие пробелы?
 
K

Kee_Keekkenen

т.к. я не нашел красивого решения с обработчиком ошибок, то использую только процедуру
Код:
Sub ErrH(thread As String, condition As Boolean)	
%REM
Вывод сообщения об ошибке		
%END REM
Dim msg As String
msg = "Ошибка " + Cstr(Err) + ": " + Error + ", в строке " + Cstr(Erl) + " в процессе " + thread + " (" + procID	+ ")"
If condition Then
Msgbox msg, 16, "Lotus Notes error"		
Else
Print msg 		
End If	
End Sub

только procID глобально использую, но можно и без нее

Код:
Function f()

try:
On Error Goto catch
'..
Exit Function
catch:
Call errh( Getthreadinfo(1), False)
Exit Function
end function

можно, конечно классы, синглетоны или еще что-то использовать, но как-то нет в этом особого преимущества
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
Не моё, но постараюсь ответить)

- зачем собсно одновременно используется print и msgbox?
Затем, что когда у пользователя возникает ошибка, то он зовёт админа и ждёт, потом устаёт ждать и закрывает сообщение, зато в статусбаре сообщение остаётся, и его можно какое-то время посмотреть. Естественно для сервера это ненужно.
Конечно же, если обработчик объединён с системой логирования, то и админу/разрабу никуда ходить ненужно...

- у Err и Error глобальная область видимости, зачем передавать их в обработчик?
В нескольких версиях шестёрки был баг (или фича?), что они видны только на этом же уровне и выше.. если же идёшь в специальную процедуру записи ошибок (ниже), то значения терялись, поэтому передаю параметрами до сих пор, на всякий случай.
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
т.к. я не нашел красивого решения с обработчиком ошибок, то использую только процедуру
можно, конечно классы, синглетоны или еще что-то использовать, но как-то нет в этом особого преимущества
Сам когда-то "процедурный подход" для этого использовал.. но когда реализуешь не только вывод сообщения, а и привязываешь к этому выход вверх с сохранением параметров во всех вышележащих обработчиках ошибок, плюс ещё в самом обработчике может быть ошибка, а это уже другая ошибка, а надо сохранить обе + логирование, тогда классы очень полезны, т.к. если это всё реализовать на функциях, то возникнет необходимость в куче глобальных переменных... это очень красиво решает класс :( Инициализируется он один раз на Initialize самой низкоуровневой библиотеки..
 
H

hosm

- зачем собсно одновременно используется print и msgbox?
это не всегда удобно.
пользователь, кстати, может запросто скопипастить сообщение из мессаджбокса специально для разработчика :(
+ для веб-агента, например, print может попадать в окно браузера, а msgbox - в лог сервера.
 
T

turumbay

это не всегда удобно.
пользователь, кстати, может запросто скопипастить сообщение из мессаджбокса специально для разработчика :(
+ для веб-агента, например, print может попадать в окно браузера, а msgbox - в лог сервера.
для веб-агента такой обработчик - вообще смерть. здесь вызывающая функция не узанет, что внутри вызываемой возникла ошибка и продолжит работать как ни в чем не бывало. т.е. в нормальный выхлоп верхней( нижней с точки зрения стека ) функции попадет этот принт... Посреди разметки этакий превед :)
А скопипастить че-нить из msgbox мне ни разу не удавалось :) PrintScreen-ом если только...

to VladSh
Конечно же, если обработчик объединён с системой логирования, то и админу/разрабу никуда ходить ненужно...
но мы же видим, что объединен. cscLOG именно этим походу и занимаеца.
В нескольких версиях шестёрки был баг (или фича?), что они видны только на этом же уровне и выше.. если же идёшь в специальную процедуру записи ошибок (ниже), то значения терялись, поэтому передаю параметрами до сих пор, на всякий случай.
Я не встречал описанного поведения в шестерке( сидели на 6.0.2cf1 ), так что тут вы возможно правы. Но шестерка - это прошлый век. Ее вроде и с поддержки уже сняли. Это как писать паблик сайты с оглядкой на ie6...
Приведенная функция получает 6(!) параметров на входе в неочевидном порядке. Это же абзац. Ее можно юзать только через copy-paste.
При том что вся необходимая информация есть в глобальных err , errror$, а остальное можно вытащить из Lsi_info(14). Единственное, чего нет - это module_name(точнее, он есть - но всегда). вот его и надо передать обработчику.
З.Ы. слухи о падении серверов при использовании Lsi_info сильно преувеличены.
 
A

Akupaka

А скопипастить че-нить из msgbox мне ни разу не удавалось
Почти в любом сообщении Ctrl+C :(

получается такое (при попытке выполнить непонятное приложение из Пуск/Выполнить):
[Window Title]
asdsadas

[Content]
Windows не може знайти "asdsadas". Перевірте правильність імені та повторіть спробу.

[ОК]
ЗЫ: круто! в 7-ке прям разделы как в ini. Раньше было разделено минусами.

зы:
turumbay, критичный подход это хорошо, но стоит ли в этой теме обсуждать чужой стиль написания кода?
Думаю, для этого будет лучше использовать другую тему. А?
 
N

nvyush

А скопипастить че-нить из msgbox мне ни разу не удавалось :) PrintScreen-ом если только...
Ctrl+C — и будет Вам счастье...
turumbay сказал(а):
Единственное, чего нет - это module_name(точнее, он есть - но всегда)
Эту фразу не понял, но если кто поделится, как в клиенте узнать имя модуля с помощью функций Getthreadinfo или Lsi_info — буду премного благодарен (и, видимо, не я один).
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
но мы же видим, что объединен. cscLOG именно этим походу и занимаеца.
Я не смотрел чем занимается cscLOG (давно пересмотрел их гору, все не понравились, - написал свой), просто отвечал на вопросы.
Но шестерка - это прошлый век. Ее вроде и с поддержки уже сняли. Это как писать паблик сайты с оглядкой на ie6...
6-ка куплена официально у многих компаний, и доплачивать деньги за переход мало кто будет... поэтому компании-разработчики ПО в основном вынуждены поддерживать совместимость.
Переход, по моему, будет оправдан, когда XPages доточат до нормального уровня.
Приведенная функция получает 6(!) параметров на входе в неочевидном порядке. Это же абзац. Ее можно юзать только через copy-paste.
Может и 6, не видел. У меня 4 (в очевидном порядке), что устраивает.
 
A

Akupaka

Эту фразу не понял
Lsi_info в одном из параметров возвращает (14?), но на сервере (раньше, щас не знаю) возвращалось не корректное имя либы, а какой-то код.
А "он есть - но всегда" означает, что значение имени модуля необходимо передавать из места вызова обработчика, т.к. в самой процедуре обработчика можно получить лишь имя модуля, в котором именно она находится, а не там где произошла ошибка.
 
T

turumbay

turumbay, критичный подход это хорошо, но стоит ли в этой теме обсуждать чужой стиль написания кода?
Думаю, для этого будет лучше использовать другую тему. А?[/size]
сначала человек спрашивает, как получить первые три символа в строке:
как из строки получить первые n-символов, к примеру первые три? О_0
, а потом вставляет пример кода. код явно чужой, копирайтов нет, вопщем неаккуратненько как-то. желание порисоваца понятно, но надо же совесть иметь...
P.S. Про ctrl+c - спасибо, не знал. Как говорица, "о сколько нам открытий чудных..."
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
пользователь, кстати, может запросто скопипастить сообщение из мессаджбокса специально для разработчика
Пользователь, который знает об этом, - 1 из 100, в лучшем случае 1 их 50-ти..

круто! в 7-ке прям разделы как в ini. Раньше было разделено минусами.
Думаю, это не от версии клиента зависит (у меня в 8-ке всё по старому), а от чего-то в ОСи..


nvy, если код выполняется на сервере, то Lsi_info(3) и Lsi_info(13) возвращает нормальное читаемое значение..
Lsi_info(3) - Current module (*)
Lsi_info(13) - Calling module that called this sub or function (*)
* - this call returns a hex code, not the module name
Кто-нибудь знает, как перевести hex в нормальный стринг (для клиента)?

Добавлено:
P.S. Про ctrl+c - спасибо, не знал. Как говорица, "о сколько нам открытий чудных..."
Скопировать текущее окошко в буфер в виде картинки - Alt+PrtSc.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!