Страница 1 из 2
Abnormal Termination Firebird 1.5.3.4870
Добавлено: 14 сен 2006, 12:06
Valmir
Есть база на firebird 1.5.3.4870 и прога-клиент; одна из процедур базы использует функцию, реализованную в dll; естестенно dll лежит в папке UDF и все параметры функции описаны, а именно:
DECLARE EXTERNAL FUNCTION CALCPRICE
VARCHAR(255),
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
INTEGER
RETURNS DOUBLE PRECISION FREE_IT
ENTRY_POINT 'CalcPrice' MODULE_NAME 'MyDLL.dll'.
На моем компе или если подключаться с других компов, вызов вышеупомянутой процедуры проходит корректно. Но на серваке клиентов, время от времени при вызове процедуры сервак firebird сваливается.
В логах firebird написано следующее:
ARCTURUS (Server) Thu Sep 07 14:47:22 2006
Access violation.
The code attempted to access a virtual
address without privilege to do so.
This exception will cause the Firebird server
to terminate abnormally.
ARCTURUS (Client) Thu Sep 07 14:47:22 2006
C:\Program Files\Firebird\Firebird_1_5\bin\fbserver.exe: terminated abnormally (4294967295)
В журнале событий винды такоесообщение:
The description for Event ID ( 281 ) in Source ( FirebirdGuardianDefaultInstance ) cannot be found. The local computer
may not have the necessary registry information or message DLL files to display messages from a remote computer. You may
be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following
information is part of the event: Abnormal Termination: C:\Program Files\Firebird\Firebird_1_5\bin\fbserver.exe:
terminated abnormally (4294967295)r.exe
При чем заметили такую особенность, при первом вызове процедуры с клиента, почти 100%, что сервак свалиться, если потом сделать на клиенте реконект, то процедура с теми же параметрами выполняется без ошибок, и дальнейшие вызовы проходят нормально. Потом, если отключиться клиентом от базы, подождать какое-то время и подключится и снова выполнить процедуру снова ошибка.
Пожет кто подсказать в чем дело? Вобще впечатление, что винда или фаерволы/антивири, время от времени не дают firebird получить доступ к dll или самой dll не дают нормально работать с ыделением памяти.
Re: Abnormal Termination Firebird 1.5.3.4870
Добавлено: 14 сен 2006, 12:09
dimitr
Valmir писал(а):RETURNS DOUBLE PRECISION FREE_IT
это шутка такая?
Добавлено: 14 сен 2006, 12:13
kdv
если обращение к udf валит сервер, то udf написана криво. про free_it для double уже сказали, это как минимум...
Добавлено: 14 сен 2006, 12:38
Valmir
Может я чего-то недопонимаю...
Заголовок в функции dll следующий:
Код: Выделить всё
function CalcPrice(Formula: PChar; var PriceDiler, PriceIn, RateDiler,
RateIn, RateOut, Coef: double; var PriceType: integer): PDouble; cdecl; export;
когда возвращал просто Double, то выдавалось левое число.
free it сдела так как PDouble, а не Double.
даже если допустить, что dll написана криво, почему тогда на моем компе все нормально работает и ничего не падает. а на другом падает, но только иногда?
Добавлено: 14 сен 2006, 12:45
dimitr
ты в своей UDF память для результата выделяешь? Если нет, то нафига тогда FREE_IT? Если да, то показывай, как именно.
Добавлено: 14 сен 2006, 12:58
Valmir
dimitr писал(а):ты в своей UDF память для результата выделяешь? Если нет, то нафига тогда FREE_IT? Если да, то показывай, как именно.
конечно выделяю:
Код: Выделить всё
New(Result);
...
Result^ := RoundReal(Result^/RateOut, 2);
я почитал статью "Как научиться писать UDF для InterBase за 21 мин",
там прямо написано
Код: Выделить всё
function Add_B(var iSmall: SmallInt; var iLong: Integer): PInteger; cdecl; export;
замечание: с серверами архитектуры SuperServer нельзя использовать такие udf. потому что udf будет вызываться в контексте одного процесса для разных пользователей (threads), и соответственно в глобальной переменной ResultInteger будет мешанина из конкурентных значений. В SuperServer значения можно возвращать только по значению, по FREE_IT, или через входной параметр
потому и сделал по ссылке и FREE_IT
Добавлено: 14 сен 2006, 13:03
kdv
когда возвращал просто Double, то выдавалось левое число.
этот код восстановить нельзя?
New(Result);
статью ты видно НЕ ЧИТАЛ. Какой еще new для free_it ???
Добавлено: 14 сен 2006, 13:12
Valmir
kdv писал(а):когда возвращал просто Double, то выдавалось левое число.
этот код восстановить нельзя?
New(Result);
статью ты видно НЕ ЧИТАЛ. Какой еще new для free_it ???
код восстановить можно, но говорю ж возвращалось левое число
NEW(result) - выделяет память под PDouble и делает result ссылкой на этот адрес памяти, да в статье сделана глобальная переменная, а значение функции становится ссылкой на эту переменную, только какой смысл, чем плох New ?
может я недопонимаю смысл Free_it? в статье не описано, что реально происходит....
Добавлено: 14 сен 2006, 13:21
dimitr
FREE_IT заставляет сервер освобождать за тобой память. Неужто трудно догадаться, что он это делает отнюдь не дельфовым менеджером памяти? Для FREE_IT ты обязан выделять память *только* через ib_util_malloc().
Добавлено: 14 сен 2006, 13:25
Valmir
хорошо Free_it освобождает память, тогда чем плох мой вариант?
функция в dll выделила под свой результат память, вернула firebird значение buReference, т.е. ссылкой на адрес этой памяти, что тут плохого? в чем некорректность dll?
Добавлено: 14 сен 2006, 13:30
dimitr
в том, что память выделена в дельфовой куче, а сервер ее освобождает через сишную free().
Добавлено: 14 сен 2006, 13:42
Valmir
dimitr писал(а):в том, что память выделена в дельфовой куче, а сервер ее освобождает через сишную free().
это понятно, но тогда пожалуйста дайте ответ на встречные вопросы
1. допустим делаем так: функция dll возвращает тип Double, тогда можно ложить значение прямо в Result функции или необходимо делать глобальную переменную?
2. Если делать глобальную переменную, то как будет работать в многопоточности? т.к. в статье как-то неоднозначно сказано:
Код: Выделить всё
с серверами архитектуры SuperServer нельзя использовать такие udf. потому что udf будет вызываться в контексте одного процесса для разных пользователей (threads), и соответственно в глобальной переменной ResultInteger будет мешанина из конкурентных значений. В SuperServer значения можно возвращать только по значению, по FREE_IT, или через входной параметр
- вобще исходя из данного куска складывается мнение, что если делаем byReference, то надо делать Free_it, чтобы был корректный резальтат в многопоточности
3. если вобще не делать Free_it, то тогда как будет освобождаться память из дэлфевой кучи после многократного вызова функции из dll
Добавлено: 14 сен 2006, 13:47
Valmir
Наверное уже достал, но надеюсь посдледний вопрос:
будет ли корректно работать в многопоточности и корректно выделяться/освобождаться память если делать так:
Код: Выделить всё
function CalcPrice(Formula: PChar; var PriceDiler, PriceIn, RateDiler,
RateIn, RateOut, Coef: double; var PriceType: integer): Double; cdecl; export;
в теле функции не делаем никакого выделения памяти, и значение ложим прямо в результат.
в базе делаем возврат byValue и не делаем Free_if?
такой вариант корректный во всех ракурсах?
Добавлено: 14 сен 2006, 13:53
Dimitry Sibiryakov
Да, будет корректно работать в многопоточности.
Если не будете выделять память то не будет и ошибок с ее освобождением.
Основные баги обычно кроются не в заголовке функции а в ее коде.
Добавлено: 14 сен 2006, 15:25
kdv
про free_it дополнительно написано в faq.
www.ibase.ru/ibfaq.htm#free_it
но в данном случае тебе free_it не нужен.
Добавлено: 14 сен 2006, 16:12
Valmir
а сервак все равно продолжает падать
текст функции в dll:
Код: Выделить всё
function CalcPrice(Formula: PChar; var PriceDiler, PriceIn, RateDiler,
RateIn, RateOut, Coef: double; var PriceType: integer): Double;
var
i, j: integer;
KeyLen: Word absolute Formula;
KeyStr: PChar;
s: String;
begin
PriceDiler := PriceDiler*RateDiler;
PriceIn := PriceIn*RateIn;
case PriceType of
-2: Result := PriceDiler*Coef;
-3: Result := PriceIn*Coef;
else
begin
KeyStr := AllocMem(KeyLen + 1);
Move((Formula + 2)^, KeyStr^, KeyLen);
s := KeyStr;
s := AnsiReplaceText(AnsiLowerCase(s), '[pricediler]', FloatToStr(PriceDiler));
s := AnsiReplaceText(s, '[pricein]', FloatToStr(PriceIn));
s := AnsiReplaceText(s, ',', '.');
Result := CalcFunction(s, 0, 0, 0);
FreeMem(KeyStr, KeyLen+1);
end;
end;
Result := RoundReal(Result/RateOut, 2);
end;
память если и выделяется дэлфей, то тут же освобождается
в базе функция определена так:
Код: Выделить всё
DECLARE EXTERNAL FUNCTION CALCPRICE
VARCHAR(255),
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
DOUBLE PRECISION,
INTEGER
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'CalcPrice' MODULE_NAME 'MyDll.dll'
при первом вызове сервак падает, после реконекта все хорошо работает. если отключится выждать время 1-4 мин, то опять при первом обращении падает. такая ситуация именно на серваке клиентов. при тестировании на наших компах все нормально. в чем же все таки дело?
Добавлено: 14 сен 2006, 16:56
dimitr
Valmir писал(а):текст функции в dll:
Код: Выделить всё
function CalcPrice(Formula: PChar; var PriceDiler, PriceIn, RateDiler,
RateIn, RateOut, Coef: double; var PriceType: integer): Double;
cdecl ты из вредности убрал?
Добавлено: 14 сен 2006, 16:57
kdv
при первом вызове сервак падает
в конце статьи
www.ibase.ru/devinfo/udf_ok.htm есть описание как отлаживать UDF в Delphi. Тем более, если сервак валится при первом же вызове.
Кстати, а зачем вот это AllocMem, Move и т.п. ? Да еще блин с такими опасными древностями типа word absolute formula...
Добавлено: 15 сен 2006, 07:30
Valmir
To dimitr: cdecl есть в заголовке процедуры в начале юнита, я запостил код реализации потому и нету cdecl и export;
To kdv:
1. может и древности, но работающие корректно или вы хотите сказат что такая реализация некорректная?
2. читайте внимательно я же четко написал: на моем компьютере все работает корректно, ничего не сваливается, функция возвращает правильный результат. Но когда тестируем программу на серваке клиентов, то только тогда сервак firebird падает, при чем только первый раз, после реконекта все работает нормально. Я именно это не могу понять, если предположить что dll написана криво, то почему у меня ничего не падает, а у них падает но иногда?
Добавлено: 15 сен 2006, 10:42
kdv
Valmir. ТАК уже никто не пишет. Так когда-то писали под досом, где шансов получить AV почти не было, и утечки памяти никого не интересовали.
читать
внимательно нужно вам - я объяснил, как отлаживать udf, что настоятельно рекомендую сделать, как и переписать этот странный и местами лишний код. Именно потому что у вас на сервере эта udf падает.
не хотите чинить - это ваша проблема.
Я именно это не могу понять, если предположить что dll написана криво, то почему у меня ничего не падает, а у них падает но иногда?
не надо ничего тут понимать. Возьмите программу с утечками памяти и неверной адресацией, и она будет глючить на двух компьютерах по разному.
И кривые udf именно так и ведут себя. они могут глючить при первом запуске, при десятом, или вообще на специфических данных.