Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Fail, Fail & constructor 
:(
    Опции темы
pascal
  Дата 29.3.2004, 03:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 16.7.2003
Где: Россия - Уфа

Репутация: нет
Всего: 1



Может кто знает почему когда я вызываю Fail в конструкторе класса, которой создаёться вне try при завершении программы возникает ошибка...

Пример:

Код
constructor TDB.Create;
...
begin
...
 Fail;
...
end;


если я в dpr проекте попытаюсь создать объект и если Fail будет выполнена, то либо при создании проекта будет ошибка, либо при завершении работы возникнет ошибка, причём в модуле system в процедуре UnsetExceptionHandler...

Например:

Код
...
 Application.Initialize;
 DB := TDB.Create;
...

будет ошибка
а если вот так
Код
...
 Application.Initialize;
 try
   DB := TDB.Create;
 except
 end;
...

или так
Код
...
 Application.Initialize;
 try
   DB := TDB.Create;
 finally
 end;
...

то всё ок...

Но почему???

(для тех кто не знает: Fail может быть вызвана в функции типа constructor и она удаляет созданный объект из памяти и TObject.Create возврощает nil)

PS: Не надо предлагать перенсти этот фрагмент кода в try, как это в работоспособных примерах, меня суть ошибки интересует...
PM MAIL WWW ICQ   Вверх
p0s0l
Дата 29.3.2004, 06:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Г-н Посол
****


Профиль
Группа: Экс. модератор
Сообщений: 3668
Регистрация: 13.7.2003
Где: 58°38' с.ш. 4 9°41' в.д.

Репутация: 58
Всего: 112



В D7 сразу видно, что компилится по-левому, т.к. esp не восстанавливается...
Пример:
Код
 TMy = class
 public
   constructor Create;
 end;

constructor TMy.Create;
begin
 inherited create;
 Fail;
end;

Компилится так:
Код
//begin
push ebx
push esi
test dl, dl
jz +$08
add esp, -$10 // !!!!!!
call @ClassCreate
mov ebx, eax
mov esi, eax
// inherited Create
xor edx, edx
mov eax, esi
call TObject.Create
// Fail
mov edx, ebx
mov eax, esi
call @Fail
jmp +$17 // прыжок на end
...
// end
pop esi
pop ebx
ret

Видно, что после add esp, -$10 надо бы его как-то восстановить, но Fail без раздумьев прыгает на pop esi, pop ebx, ret так и не восстановив esp... Остюда и вся лажа...
Для данного случая можно сделать свой Fail:
Код
var adr : pointer;
procedure MyFail;
begin
 asm
   mov [adr], eax
 end;
 FreeMem(adr);
 asm
   xor eax, eax
   add esp, $14
   pop esi
   pop ebx
   ret
 end;
end;

constructor TMy.Create;
begin
 inherited create;
 MyFail;
end;

add esp, $14 - это из-за того, что в конструкторе делали add esp, -$10 и вызывали MyFail (4 байта в стеке)...

Добавлено @ 06:56
pascal, тебе же может надо будет делать не $14, а побольше (но кратно 4). Посмотри у себя, насколько портится esp...


Добавлено @ 06:58
А, да, еще может не только pop esi, pop ebx делать надо, но и еще какой-нибудь pop - посмотри код твоего конструктора (в отладке View->Debug Windows->CPU window)...



--------------------
С уважением, г-н Посол.
PM   Вверх
pascal
Дата 29.3.2004, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 16.7.2003
Где: Россия - Уфа

Репутация: нет
Всего: 1



нет, в чём то другом дело... делаю так
Код
 asm
   push esi;
 end;
   DB := TDB.Create;
 asm
   pop esi;
 end;


всё равно не работает, ошибка там же...

то есть вот так

Код
 asm
   push esp;
 end;
   DB := TDB.Create;
 asm
   pop esp;
 end;


всё равно там же ошибка

Это сообщение отредактировал(а) pascal - 29.3.2004, 15:25
PM MAIL WWW ICQ   Вверх
pascal
Дата 29.3.2004, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 16.7.2003
Где: Россия - Уфа

Репутация: нет
Всего: 1



> DB := TDB.Create;

Код
mov dl, $01
mov eax, [$00466a28]
call TDB.Create


при выполнении последней строки изменяються регистры:
EAX - 00466A74 -> 00000000
EBX - 7FFDF000 -> 0012FFA0
ECX - 0012FF9C -> 00000000
EDX - 0012FF01 -> 00000000
ESI - 00000000 -> 004671C2
EDI - 00000000 -> 0012FF48



PM MAIL WWW ICQ   Вверх
pascal
Дата 29.3.2004, 22:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 16.7.2003
Где: Россия - Уфа

Репутация: нет
Всего: 1



Код

изменения регистра ESP с try

begin  - +4 - FFAC -> FF9C
try    - +3 - FF9C -> FF90
except - -3 - FF90 -> FF9C
end    - -4 - FF9C -> FFAC

изменения регистра ESP без try

begin  - +1 - FFAC -> FFA8
end    - -1 - FFA8 -> FFAC

createDB с try

function CreateDB: TDB;
begin
 try
   Result := TDB.Create;
 except
 end;
end;

при вызове CreateDB изменяються регистры: EAX, ECX

createDB без try

function CreateDB: TDB;
begin
 Result := TDB.Create;
end;

при вызове CreateDB изменяються регистры: EAX, EBX, ECX, EDX, ESI, EDI

createDB с push и pop try

function CreateDB: TDB;
begin
   asm
     push ebx
     push edx
     push esi
     push edi
   end;
   Result := TDB.Create;
   asm
     pop  edi
     pop  esi
     pop  edx
     pop  ebx
   end;
end;

при вызове CreateDB изменяються регистры: EAX, ECX

но оказалось что не в регистрах то дело...

Есть другай мысль... Надо отследить сам код это try...

> код TDB.Create
mov dl, 1
mov eax, *
call TDB.Create

> try
xor eax, eax
push ebp
push *
push dword ptr fs:[eax]

> try (после кода)
xor eax, eax
pop edx
pop ecx
pop ecx
mov fs:[eax], edx
jmp [end]

и так я сделал альтернативу

 try
   Result := TDB.Create;
 except
 end;

вот так

 asm
   xor eax, eax
   push dword ptr fs:[eax]
 end;
   Result := TDB.Create;
 asm
   mov ecx, eax
   xor eax, eax
   pop edx
   mov fs:[eax], edx
   mov eax, ecx
 end;

вроде работает, но как всётаки без этого обойтись???
PM MAIL WWW ICQ   Вверх
p0s0l
Дата 30.3.2004, 13:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Г-н Посол
****


Профиль
Группа: Экс. модератор
Сообщений: 3668
Регистрация: 13.7.2003
Где: 58°38' с.ш. 4 9°41' в.д.

Репутация: 58
Всего: 112



Цитата(pascal @ 29.3.2004, 15:08)
нет, в чём то другом дело... делаю так
Код
 asm
   push esi;
 end;
   DB := TDB.Create;
 asm
   pop esi;
 end;


всё равно не работает, ошибка там же...

то есть вот так

Код
 asm
   push esp;
 end;
   DB := TDB.Create;
 asm
   pop esp;
 end;


всё равно там же ошибка

pascal, ошибка-то возникает в конструкторе, зачем push и pop делать где-то там, в далеке ? Что, каждый раз так будешь делать ? Я же привел пример, как исправить сам конструктор (вместо Fail делать MyFail)... Приведи асм-листинг самого конструктора (начиная с begin) - я тебе напишу, как у тебя будет выглядеть MyFail.
Ошибка возникает, как я сказал, из-за того, что esp при Fail не восстанавливается, а значит pop esi и pop ebx (в приведенном примере) восстанавливаются совсем по-левому, и, самое главное, ret происходит неизвестно куда, может в космос, из-за этого и появляется исключение...

Добавлено @ 13:30
Цитата
try
  Result := TDB.Create;
except
end;

вот так

asm
  xor eax, eax
  push dword ptr fs:[eax]
end;
  Result := TDB.Create;
asm
  mov ecx, eax
  xor eax, eax
  pop edx
  mov fs:[eax], edx
  mov eax, ecx
end;


вроде работает, но как всётаки без этого обойтись?

Ага, зачем try..except заменять на asm-аналог ? Быстрее try-except написать, чем всё это, и будет то же самое...


--------------------
С уважением, г-н Посол.
PM   Вверх
pascal
Дата 30.3.2004, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 16.7.2003
Где: Россия - Уфа

Репутация: нет
Всего: 1



Я придумал, вот так работает

Код
asm
 add esp, $0C
 pop dword ptr fs:[0]
end;
Fail;


тока в теле try слишком сильно сбиваеться esp и восстановить его весьма сложно

то есть вот так уже работать не будет

Код

try
 asm
   add esp, $0C
   pop dword ptr fs:[0]
 end;
 Fail;
except
end;

или
Код

try
...
except
 asm
   add esp, $0C
   pop dword ptr fs:[0]
 end;
 Fail;
end;

PM MAIL WWW ICQ   Вверх
p0s0l
Дата 30.3.2004, 15:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Г-н Посол
****


Профиль
Группа: Экс. модератор
Сообщений: 3668
Регистрация: 13.7.2003
Где: 58°38' с.ш. 4 9°41' в.д.

Репутация: 58
Всего: 112



А зачем pop dword ptr fs:[0] ? Это же в случае try..except...
Просто add esp, $10 не работает ?



--------------------
С уважением, г-н Посол.
PM   Вверх
pascal
Дата 30.3.2004, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 180
Регистрация: 16.7.2003
Где: Россия - Уфа

Репутация: нет
Всего: 1



Цитата
Просто add esp, $10 не работает ?

Неа, не работает...

В FS:[0] Delphi переодически esp сохраняет... а сам esp и с "add esp, $10" и без него не меняеться в результате...
PM MAIL WWW ICQ   Вверх
p0s0l
Дата 31.3.2004, 06:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Г-н Посол
****


Профиль
Группа: Экс. модератор
Сообщений: 3668
Регистрация: 13.7.2003
Где: 58°38' с.ш. 4 9°41' в.д.

Репутация: 58
Всего: 112



Код
В FS:[0] Delphi переодически esp сохраняет...

Если ты пользуешь try - тогда и сохраняет...
Код
сам esp и с "add esp, $10" и без него не меняеться в результате...
Ты поди понял так, что add esp,$10 надо вместо pop делать ? Я имел в виду, что надо вместо add esp, $0c + pop делать add esp,$10...
Esp в обоих случаях будет одинаковым, к твоему сведениюsmile.gif:
1. add esp, $10
2. add esp, $0c; pop dword ptr fs:[0]
Так что что-то ты там намудрил, или неправильно понял...
pop dword ptr fs:[0] не восстанавливает esp, а заносит по этому адресу fs:[0] dword из стека.

Вот способ Fail, работающий хоть в try..except, хоть без него:
Код
var  old_esp : dword;

constructor TMy.Create;
begin
asm
  mov [old_esp], esp
end;

inherited create;

try

asm
  mov esp, [old_esp]
  add esp, $10
end;
Fail;

except
end;
end;



--------------------
С уважением, г-н Посол.
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0535 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.