?

Log in

No account? Create an account
Red with green eyes

falcrum


Falcrum - изба-читальня

Отзывы о прочтённых мной книгах, дневники личных путешествий и размышлизмы


Previous Entry Share Next Entry
А вот кто ещё помнит седьмой Delphi?
Violet smoker
falcrum
Коллегу попросили слегка поколупаться в старом проекте:



Приходит ко мне - грит, я в шоке: убил полдня - задница! Ничего не понимаю! Не работает! Давай вместе посмотрим!

Итак, имеется DLL-ка, в ней две функции:

Load1: function (aS: pChar): boolean; stdcall = nil;
Load2: function (aS: pChar; var codeErr: LongInt): boolean; stdcall = nil;


Инициализация:

@Load1 := GetProcAddress (hLib, 'Load1');
@Load2 := GetProcAddress (hLib, 'Load2');


Вызов Load1:

procedure PerformLoad (TaskObject: TTaskObject);
var
ErrorCode: integer;
s: string;
begin
s := TaskObject.RequestText;
if Load1 (@s[1]) then // вызов старой функции библиотеки
ErrorCode := 0
else
ErrorCode := 1;
TaskObject.ErrorCode := ErrorCode;
end;


Вызов снаружи:

// Инициализация объекта LocalTaskObject
...
PerformLoad (LocalTaskObject);
if (LocalTaskObject.ErrorCode = 0) then
...


Всё работало. Но. Надо ему было заменить Load1 на Load2:

procedure PerformLoad (TaskObject: TTaskObject);
var
ErrorCode: Integer;
s: string;
begin
s := TaskObject.RequestText;
Load2 (@s[1], ErrorCode); // вызов новой функции библиотеки
TaskObject.ErrorCode := ErrorCode;
end; //Вот здесь ещё всё хорошо - объект TaskObject в отладчике "живой"


И внезапно:

// Инициализация объекта LocalTaskObject
...
PerformLoad (LocalTaskObject); // передаём "живой" объект
if (LocalTaskObject.ErrorCode = 0) then // и внезапно вот здесь LocalTaskObject становится nil
...


Увидев подобное, я несколько прифигел. В чём разница? Что может освобождать или затирать объект? Ладно, говорю, давай попробуем тупой костыль:

function PerformLoad (TaskObject: TTaskObject): TTaskObject;
var
ErrorCode: integer;
s: string;
begin
s := TaskObject.RequestText;
Load2 (@s[1], ErrorCode); // вызов новой функции библиотеки
TaskObject.ErrorCode := ErrorCode;
result := TaskObject;
end;
// Вызов
// Инициализация объекта LocalTaskObject
...
LocalTaskObject := PerformLoad (LocalTaskObject); // передаём "живой" объект
if (LocalTaskObject.ErrorCode = 0) then // и внезапно всё опять заработало
...


Но как?


  • 1
Что-то не так нахакано и трется по ходу стек. Конкретно в виде переменной LocalTaskObject. Перезапись естественно помогает.

Отладчик в руки и смотреть когда и где и как трется.

Edited at 2014-09-02 08:07 am (UTC)

PS: Кстати совершенно не факт, что раньше стек не терся - возможно просто мелкое изменение проявило ошибку.

Ставишь watch на LocalTaskObject и просто прощелкиваешь по шагам - и смотришь где он трется. Ну и там разбираешься.

Реально скорее всего х-ня в Load2 с соглашениями о связях или чем там ищо.

А там точно stdcall, а не cdecl должен быть? Первый обычно только у winapi.

Не, длл-ка на дельфях же - всё ок.

Почему stdcall-то? В дельфях же register стандартная, нет?

Если я правильно помню, ещё с паскаля нестандартная.

Ищите соседний поток. Или баг с затиранием памяти в DLL.

И да, "заработало" - это оно будет падать теперь только при определенной фазе луны и наполнении памяти, готовьтесь к невоспроизводимым баг-репортам.


Edited at 2014-09-02 08:06 am (UTC)

ErrorCode: integer;
и
var codeErr: LongInt

ИМХО стек затирается

Не собралось бы, компилятор возмутится.

Не, дельфя с таким умная...

Скорее, поток. Но как-то он аккуратно "затирает"...

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

  • 1